k进制FWT学习笔记

从线性代数角度看快速变换

考虑我们现在对两个幂级数 A , B A,B A,B 定义运算 ∗ * :

假设 A ∗ B = C A*B=C AB=C ,那么要求满足 C k = ∑ i ⊕ j = k A i B j C_k=\sum\limits_{i\oplus j=k}A_iB_j Ck=ij=kAiBj ,现在给出 A , B A,B A,B ,要求快速求出 C C C

于是我们考虑构造矩阵 f f f 满足 ( f ∗ A ) ∗ ( f ∗ B ) = ( f ∗ C ) (f*A)*(f*B)=(f*C) (fA)(fB)=(fC) f f f 可逆,那么现在只需快速求出 f ∗ A , f ∗ B , f − 1 ( f ∗ C ) f*A,f*B,f^{-1}(f*C) fA,fB,f1(fC)即可。

不难发现当 ⊕ \oplus 为加法时我们的 f f f 即是系数表示法到点值表示法的转移矩阵。

现在考虑推导 K K K 进制 F W T FWT FWT 的系数矩阵:

不妨设 n = K i − 1 n=K^i-1 n=Ki1 ,那么有
( f ∗ A ) [ x ] ∗ ( f ∗ B ) [ x ] = ( f ∗ C ) [ x ] ( ∑ i = 0 n f x , i a i ) ( ∑ i = 0 n f x , i b i ) = ∑ i = 0 n f x , i c i f x , k = ∑ i ⊕ j = k f x , i f x , j \begin{aligned}(f*A)[x]*(f*B)[x]=&(f*C)[x]\\(\sum\limits_{i=0}^{n}f_{x,i}a_i)(\sum\limits_{i=0}^nf_{x,i}b_i)=&\sum\limits_{i=0}^nf_{x,i}c_i\\f_{x,k}=&\sum\limits_{i\oplus j=k}f_{x,i}f_{x,j}\end{aligned} (fA)[x](fB)[x]=(i=0nfx,iai)(i=0nfx,ibi)=fx,k=(fC)[x]i=0nfx,iciij=kfx,ifx,j
显然光靠这点是不够的,我们需要给 f i , j f_{i,j} fi,j 赋予更强的性质:假设当前有 m + 1 m+1 m+1 K K K 进制位, x = ( x 0 x 1 x 2 . . . x m ) K k x=(x_0x_1x_2...x_m)_Kk x=(x0x1x2...xm)Kk ,我们构造 f x , y = ∏ i = 0 m f x i , y i f_{x,y}=\prod\limits_{i=0}^mf_{x_i,y_i} fx,y=i=0mfxi,yi

x ^ \hat x x^ 表示 x x x K K K 进制下的最高位, x ˇ \check x xˇ 表示 x x x K K K 进制下的其余位,考虑矩阵乘法的式子:
( f ∗ A ) [ x ] = ∑ i = 0 m f x , i a i = ∑ i = 0 K − 1 f x ^ , i ∑ j ^ = i f x ˇ , j ˇ a j = ∑ i = 0 K − 1 f x ^ , i ( f ∗ A i ) [ x ˇ ] \begin{aligned}(f*A)[x]=&\sum\limits_{i=0}^mf_{x,i}a_i \\=&\sum\limits_{i=0}^{K-1}f_{\hat x,i}\sum\limits_{\hat j=i}f_{\check x,\check j}a_{j}\\=&\sum\limits_{i=0}^{K-1}f_{\hat x,i}(f*A_i)[\check x]\end{aligned} (fA)[x]===i=0mfx,iaii=0K1fx^,ij^=ifxˇ,jˇaji=0K1fx^,i(fAi)[xˇ]

于是现在如果求出了 f f f ,我们可以利用分治法进行快速变换。

考虑之前推出的 f f f 元素之间的关系:
f x , k = ∑ i ⊕ j = k f x , i f x , j = ∑ [ K ∣ i + j − k ] f x , i f x , j \begin{aligned}f_{x,k}=&\sum\limits_{i\oplus j=k}f_{x,i}f_{x,j}\\=&\sum\limits_{[K|i+j-k]}f_{x,i}f_{x,j}\end{aligned} fx,k==ij=kfx,ifx,j[Ki+jk]fx,ifx,j

突然神似单位根反演???而且还要求有循环的意义,那么这启示我们定义 f i , j = ( ω k i ) j = ω k i j f_{i,j}=(\omega_{k}^i)^j=\omega_{k}^{ij} fi,j=(ωki)j=ωkij

于是
f = [ 1 1 1 ⋯ 1 1 ω k 1 ω k 2 ⋯ ω k k − 1 1 ω k 2 ω k 4 ⋯ ω k 2 ( k − 1 ) ⋯ ⋯ ⋯ ⋯ ⋯ 1 ω k k − 1 ω k 2 ( k − 1 ) ⋯ ω k ( k − 1 ) ( k − 1 ) ] f − 1 = 1 k [ 1 1 1 ⋯ 1 1 ω k − 1 ω k − 2 ⋯ ω k − ( k − 1 ) 1 ω k − 2 ω k − 4 ⋯ ω k − 2 ( k − 1 ) ⋯ ⋯ ⋯ ⋯ ⋯ 1 ω k − ( k − 1 ) ω k − 2 ( k − 1 ) ⋯ ω k − ( k − 1 ) ( k − 1 ) ] f= \left[ \begin{matrix} 1&1&1&\cdots&1\\ 1&\omega_k^1&\omega_k^2&\cdots&\omega_k^{k-1}\\ 1&\omega_k^2&\omega_k^4&\cdots&\omega_k^{2(k-1)}\\ \cdots&\cdots&\cdots&\cdots&\cdots\\ 1&\omega_k^{k-1}&\omega_k^{2(k-1)}&\cdots&\omega_k^{(k-1)(k-1)} \end{matrix} \right] \\ f^{-1}=\frac1k \left[ \begin{matrix} 1&1&1&\cdots&1\\ 1&\omega_k^{-1}&\omega_k^{-2}&\cdots&\omega_k^{-(k-1)}\\ 1&\omega_k^{-2}&\omega_k^{-4}&\cdots&\omega_k^{-2(k-1)}\\ \cdots&\cdots&\cdots&\cdots&\cdots\\ 1&\omega_k^{-(k-1)}&\omega_k^{-2(k-1)}&\cdots&\omega_k^{-(k-1)(k-1)} \end{matrix} \right] f=11111ωk1ωk2ωkk11ωk2ωk4ωk2(k1)1ωkk1ωk2(k1)ωk(k1)(k1)f1=k111111ωk1ωk2ωk(k1)1ωk2ωk4ωk2(k1)1ωk(k1)ωk2(k1)ωk(k1)(k1)

例题:[清华集训2016]石家庄的工人阶级队伍比较坚强
代码:

#include
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int N=550000;
int m,t,mod,n,trans[15][15],pw[15];
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:a-=mod;}
inline void Dec(int&a,int b){(a-=b)<0?a+=mod:a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
struct cp{
	int x,y;
	cp(int x=0,int y=0):x(x),y(y){}
	friend inline cp operator+(cp a,cp b){return cp(add(a.x,b.x),add(a.y,b.y));}
	friend inline cp operator-(cp a,cp b){return cp(dec(a.x,b.x),dec(a.y,b.y));}
	friend inline cp operator*(cp a,cp b){return cp(dec(mul(a.x,b.x),mul(a.y,b.y)),dec(add(mul(a.x,b.y),mul(a.y,b.x)),mul(a.y,b.y)));}
	friend inline cp operator^(cp a,int p){cp ret=cp(1,0);for(;p;p>>=1,a=a*a)if(p&1)ret=ret*a;return ret;}
	friend inline bool operator<(cp a,cp b){return a.x^b.x?a.x<b.x:a.y<b.y;}
}w[3],a[N],b[N];
map<cp,cp>S;
inline void exgcd(int a,int b,int&x,int&y){
	if(!b){x=1,y=0;return;}
	exgcd(b,a-a/b*b,x,y);
	int t=x;
	x=y,y=t-a/b*y;
}
inline int inv(int a){
	int x,y,b=mod;
	exgcd(a,b,x,y);
	return (x%b+b)%b;
}
inline void dft(cp*a,int type){
	cp a0,a1,a2;
	for(ri i=1;i<n;i*=3){
		for(ri j=0,len=i*3;j<n;j+=len){
			for(ri k=0;k<i;++k){
				a0=a[j+k],a1=a[j+k+i],a2=a[j+k+i*2];
				a[j+k]=a0+a1+a2;
				a[j+k+i]=a0+w[1]*a1+w[2]*a2;
				a[j+k+i*2]=a0+w[1]*a2+w[2]*a1;
				if(type==-1)swap(a[j+k+i],a[j+k+i*2]);
			}
		}
	}
}
inline void dfs(int ps,int sta,int ct1,int ct2){
	if(ps==m){b[sta].x=trans[ct1][ct2];return;}
	dfs(ps+1,sta+(pw[ps]<<1),ct1,ct2+1);
	dfs(ps+1,sta+pw[ps],ct1+1,ct2);
	dfs(ps+1,sta,ct1,ct2);
}
inline cp get(cp a,int t){return S.count(a)?S[a]:S[a]=a^t;}
int main(){
	#ifdef ldxcaicai
	freopen("lx.in","r",stdin);
	#endif
	pw[0]=1;
	m=read(),t=read(),mod=read();
	w[0]=cp(1,0),w[1]=cp(0,1),w[2]=cp(mod-1,mod-1);
	for(ri i=1;i<=m;++i)pw[i]=pw[i-1]*3;
	n=pw[m];
	for(ri i=0;i<n;++i)a[i].x=read();
	for(ri i=0;i<=m;++i)for(ri j=0;i+j<=m;++j)trans[i][j]=read();
	dfs(0,0,0,0);
	dft(a,1),dft(b,1);
	for(ri i=0;i<n;++i)a[i]=a[i]*get(b[i],t);
	dft(a,-1);
	for(ri iv=inv(n),i=0;i<n;++i)cout<<mul(a[i].x,iv)<<'\n';
	return 0;
}
UPD:感谢wcr巨佬帮我修锅QwQ

你可能感兴趣的:(#,fwt)