https://www.cnblogs.com/alex-wei/p/set_power_series.html
https://www.luogu.com.cn/blog/command-block/wei-yun-suan-juan-ji-yu-ji-kuo-zhan
感觉好多人都有点误人子弟了。
高维前缀和
注意到求得是 f S = ∑ T ∈ S g T f S = ∑ T ∈ S g T ,考虑压维直接做就好了。
当然,我们在做这个东西的时候,只是用了加法的结合律、交换律。因此,取 max,min 这些运算显然也可以做。
当然,如果需要差分还原回去的话,要求运算可逆。
https://www.luogu.com.cn/problem/AT_arc100_c
FWT
本质上是做一个线性变换。
记 c ( i , j ) c ( i , j ) 为 j j 对 i i 的贡献系数,然后一顿分析后只要构造出来的 c ( i , j ) c ( i , j ) 满足 c ( i , j ⊗ k ) = c ( i , j ) c ( i , k ) c ( i , j ⊗ k ) = c ( i , j ) c ( i , k ) ,即可。又因为位运算独立,因此你可以构造出来 c ( i , j ) = c ′ ( i 0 , j 0 ) c ′ ( i 1 , j 1 ) . . . c ( i , j ) = c ′ ( i 0 , j 0 ) c ′ ( i 1 , j 1 ) . . . 这样的形式,这样你只要满足等式在所有元为 0 / 1 0 / 1 时都成立即可。记 j ⊗ k = p j ⊗ k = p ,等式即为 c ′ ( i 0 , p 0 ) c ′ ( i 1 , p 1 ) . . . = c ′ ( i 0 , j 0 ) c ′ ( i 0 , k 0 ) c ′ ( i 1 , j 1 ) c ′ ( i 1 , k 1 ) . . . = c ′ ( i 0 , j 0 ⊗ k 0 ) c ′ ( i 1 , j 1 ⊗ k 1 ) . . . c ′ ( i 0 , p 0 ) c ′ ( i 1 , p 1 ) . . . = c ′ ( i 0 , j 0 ) c ′ ( i 0 , k 0 ) c ′ ( i 1 , j 1 ) c ′ ( i 1 , k 1 ) . . . = c ′ ( i 0 , j 0 ⊗ k 0 ) c ′ ( i 1 , j 1 ⊗ k 1 ) . . . ,显然这个构造成立。
接下来,考虑分治,你注意到分治的过程的每一步都是乘上一个矩阵。
然后它这个实现的过程可以考虑当前最高位限制为 n n ,看看现在序列 f f 究竟存的是啥 f ′ ( i ) = ∑ l ≤ j < r c ( i ′ , j ′ ) f ( j ) , i ′ 为 i 保 留 前 n 位 , j ′ 同 理 f ′ ( i ) = ∑ l ≤ j < r c ( i ′ , j ′ ) f ( j ) , i ′ 为 i 保 留 前 n 位 , j ′ 同 理 ,这个东西即为定义式。然后你考虑从上次做完的结构推出来,f ′ ( i ) = ∑ l ≤ j < m i d c ( i ′ , j ′ ) f ( j ) + ∑ m i d ≤ j < r c ( i ′ , j ′ ) f ( j ) f ′ ( i ) = ∑ l ≤ j < m i d c ( i ′ , j ′ ) f ( j ) + ∑ m i d ≤ j < r c ( i ′ , j ′ ) f ( j ) ,然后把 n n 恰出去,则你会得到 f n ( i ) = c ( i n , 0 ) f n − 1 ( i ) + c ( i n , 1 ) f n − 1 ( i + 2 n − 1 ) f n ( i ) = c ( i n , 0 ) f n − 1 ( i ) + c ( i n , 1 ) f n − 1 ( i + 2 n − 1 ) 。
其实本质上我们理应更强的限制一下计算式,设做规模为 2 n 2 n 的 FWT,f ′ ( i ) = ∑ 0 ≤ j < 2 n c ( i , j ) f ( j ) f ′ ( i ) = ∑ 0 ≤ j < 2 n c ( i , j ) f ( j ) ,那么显然你最高位为 n − 1 n − 1 ,然后你把 n − 1 n − 1 提出去,发现规模缩小了一半,即两部都是 ∑ 0 ≤ j < 2 n − 1 c ( i ′ , j ′ ) f ( j ) ∑ 0 ≤ j < 2 n − 1 c ( i ′ , j ′ ) f ( j ) ,这样不难看出即为 2 n − 1 2 n − 1 规模的 FWT 做出来的答案。
然后 IFWT 的过程就是你在每一步变为乘上逆矩阵,但为啥你的方向没有变化!
我也想不明白,但是显然你回溯上去,每一步乘逆矩阵的写法一定是对的!而那些将 FWT,IFWT 整合在一起的,我感觉应该是用了结合律,交换律吧。但我还是推荐大家写开 2 种!
本质上应该都是在做一个线性变换,所以你不把它看成是逆的过程也是没事的,二者都是正确的。
然后边界问题的话,我们的过程是对原先的 f f 做线性变换,自然边界也是 f f 了。
或者理性点思考,你当最高位限制为 1 1 时,自然区间长度只有 2 2 ,此时每个数只有 1 1 位,即第 0 0 位,左边第 0 0 位为 0 0 ,右边 1 1 ,然后你考虑定义式 f ′ i = c ( 0 , 0 ) f i + c ( 0 , 1 ) f i + 1 f i ′ = c ( 0 , 0 ) f i + c ( 0 , 1 ) f i + 1 ,自然边界也是这个东西了。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int mod=998244353 ,M=(int )(1e5 ),N=(1ll <<17 )+5 ;
int fpow (int x,int y) {
int res=1 ; x%=mod;
while (y) {
if (y&1 ) res=res*x%mod; y>>=1 ; x=x*x%mod;
} return res;
}
const int inv2=fpow (2 ,mod-2 );
const int
Cor[2 ][2 ]={{1 ,0 },{1 ,1 }},
Cand[2 ][2 ]={{1 ,1 },{0 ,1 }},
Cxor[2 ][2 ]={{1 ,1 },{1 ,mod-1 }},
ICor[2 ][2 ]={{1 ,0 },{mod-1 ,1 }},
ICand[2 ][2 ]={{1 ,mod-1 },{0 ,1 }},
ICxor[2 ][2 ]={{inv2,inv2},{inv2,mod-inv2}};
int n,a[N],b[N],f[N],g[N],pre;
void FWT (int *F,const int c[2 ][2 ]) {
for (int mx=1 ;mx<=pre;mx++) {
int len=(1ll <<mx);
for (int l=0 ;l<n;l+=len) {
for (int i=l;i<l+(len/2 );i++) {
int x=F[i],y=F[i+(len/2 )];
F[i]=(c[0 ][0 ]*x%mod+c[0 ][1 ]*y%mod)%mod;
F[i+(len/2 )]=(c[1 ][0 ]*x%mod+c[1 ][1 ]*y%mod)%mod;
}
}
}
}
void IFWT (int *F,const int c[2 ][2 ]) {
for (int mx=pre;mx>=1 ;mx--) {
int len=(1ll <<mx);
for (int l=0 ;l<n;l+=len) {
for (int i=l;i<l+(len/2 );i++) {
int x=F[i],y=F[i+(len/2 )];
F[i]=(c[0 ][0 ]*x%mod+c[0 ][1 ]*y%mod)%mod;
F[i+(len/2 )]=(c[1 ][0 ]*x%mod+c[1 ][1 ]*y%mod)%mod;
}
}
}
}
void RE () {
for (int i=0 ;i<n;i++) f[i]=a[i],g[i]=b[i];
}
void PR () {
for (int i=0 ;i<n;i++) cout<<(f[i]%mod+mod)%mod<<' ' ;
cout<<'\n' ;
}
signed main () {
cin.tie (0 ); ios::sync_with_stdio (false );
cin>>n; pre=n; n=(1ll <<n);
for (int i=0 ;i<n;i++) cin>>a[i];
for (int i=0 ;i<n;i++) cin>>b[i];
RE (); FWT (f,Cor); FWT (g,Cor);
for (int i=0 ;i<n;i++) f[i]=f[i]*g[i]%mod;
IFWT (f,ICor); PR ();
RE (); FWT (f,Cand); FWT (g,Cand);
for (int i=0 ;i<n;i++) f[i]=f[i]*g[i]%mod;
IFWT (f,ICand); PR ();
RE (); FWT (f,Cxor); FWT (g,Cxor);
for (int i=0 ;i<n;i++) f[i]=f[i]*g[i]%mod;
IFWT (f,ICxor); PR ();
return 0 ;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2022-03-07 结论 区间加
2022-03-07 结论 ARC136B B - Triple Shift