ARC137-D 报灵智慧壬
作者:互联网
-
题意:
给定序列 \(\{a_n\}\) ,求出 \(a_n\) 在 \(k \in [1,m]\) 次前缀异或和后的值.
-
分析:
一个显然的事情是我会且仅会打暴力(?
赛后 \(\text{dottle}\) 过来讲题
发现它又考了一次 \(\zeta\) 变换
草, 我果然还是不会做
因为异或和加法非常像所以我们把它当成加法处理
那么就是快速求得 \(a_i\) 在 \(k\) 次前缀和中对 \(a_n\) 的贡献
这个问题实质上等价于
若在位置 \(i\) 时可以走到 \([i,n]\) 的任意位置,要用 \(k\) 步从 \(i\) 走到 \(n\) 的所有路径
这个问题实质上也就是
有 \(m\) 个无标号球,放进 \(n\) 个盒子的方案数
为了便于插板每个盒子先放一个
那么答案就是 \(\dbinom{n+m-1}{n-1}\)
所以对于 \(a_i\) ,当 \(f_i=\dbinom{n-i+k}{n-i} \mod 2 =1\) 时,对 \(a_n\) 有一次贡献
然后有一个性质:
若 \(\dbinom{n}{m} \mod 2=1\) ,当且仅当 \(n\&m=m\)
在网上搜到了一个证明,orz
但是他的 \(\LaTeX\) 好像炸了(
所以我再写一遍
证明:
\[\dbinom{n}{m}=\frac{n!}{m!(n-m)!} \]设 \(n!\) , \(m!\) , \((n-m)!\) 分解质因数后 \(2\) 的个数为 \(A\) , \(B\) , \(C\)
显然若 \(\dbinom{n}{m} \mod 2=1\) 那么一定有 \(A=B+C\)
又有性质:
其中 \(f(p,n)\) 表示 \(n!\) 质因数分解中 \(p\) 的个数, \(p \in Prime\)
结合 \(n\) 的二进制表示
那么
\[f(2,n)=\sum_{i=1}^{k}\lfloor \frac{\sum_{j=1}^{k}a_j\times2^{j-1}}{2^i} \rfloor \]其中 \(k\) 为 \(bit(n)\) 的位数
所以
(关于这一步的舍入在后文有证明)
写得更好看就是
故
\[f(2,n)=n-\text{popcount}(n) \]再设 \(n\) , \(m\) , \((n-m)\) 的 \(\text{popcount}\) 为 \(a\) , \(b\) , \(c\)
那么
也就是说
\[a=b+c \]观察可以发现当且仅当 \(bit(m) \subseteq bit(n)\)
也就是说 \(n\&m=m\)
\(\text{Q.E.D.}\)
证明了这个性质后,我们把贡献还原回异或,发现一个 \(a_i\) 在第 \(k\) 轮对 \(a_n\) 产生一次 \(\text{XOR}\) 贡献当且仅当
\[\dbinom{n-i+k}{n-i}\mod2=1 \]那么就有
\[(n-i+k)\&(n-i)=(n-i) \]因为这个柿子又等价于
\[k\&(n-i)=0 \]所以
\[\complement_{u}(k)\&(n-i)=(n-i) \]据此, \(\text{dottle}\) 使用了总复杂度为 \(O(m3^{k})\) 枚举 \(\complement_{u}(k)=Mx-k\) 的子集的写法:
for(ri k=0;k<=m-1;++k){
ri ans=a[n];
for(ri id=Mx-k;id;id=(id-1)&(Mx-k)) //枚举下标中为Cu(k)子集的部分
if(id<=n) ans^=a[n-id];
writesp(ans);
}
虽然能过,但是获得了 \(3073ms\) 的优异成绩(
看着std的 \(177ms\) 我茫然失措......
然后发现这个东西其实就是对 \(Mx-k\) 求子集函数和
欸那不就 \(\text{Fast Zeta Transform}\) 了吗???
我们对全集 \(Mx\) 做一次 \(\zeta\) 变换.
具体地,我们把 \(zeta[n-i]\) 初值设置为 \(a[i]\)
求一次正常的快速zeta变换
最后在全集中找到每个 \(zeta[Mx-k]\)
此时它们已经被全部计算完毕,所以直接输出即可
ri Mx=1,t=max(n,m),p0wer=0;
while(Mx-1<=t) Mx<<=1,++p0wer;
--Mx,--p0wer;
vector<int> zeta(Mx);
for(ri j=1;j<=n;++j)
zeta[n-j]=a[j];
for(ri i=0;i<=p0wer;++i)
for(ri bits=0;bits<=Mx;++bits)
if(bits&(1<<i)) zeta[bits]^=zeta[bits^(1<<i)];
for(ri k=0;k<=m-1;++k)
writesp(zeta[Mx-k]);
为什么可以一次计算完毕呢?
因为我们进行全集的zeta变换时,同时也计算了所有子集的zeta变换
那么最终我们的算法复杂度就是 \(O(n+k2^k) \to O(n+MlogM)\) ,其中 \(M=max\{n,m\}\)
最后跑出了 \(114ms\) .
附:对证明过程中去掉下取整步骤的小学生证明
舍掉的部分为
\[\sum_{j=1}^{i}a_j2^{j-1-i} \le \sum_{j=1}^{i}2^{j-1-i}=2^{-i}\sum_{j=1}^{i}2^{j-1} \]由小学的等比数列知识可知
\[\text{RHS}=2^{-i}\times2^0\times(2^i-1)=1-2^{-i} \lt 1 \]所以它们和下取整一起去掉是正确的
\(\text{Q.E.D.}\) (雾
标签:ARC137,times2,dbinom,text,sum,智慧,报灵,zeta,Mx 来源: https://www.cnblogs.com/suitlie/p/16210754.html