k进制FWT学习笔记

陌路散爱 提交于 2019-11-28 19:51:22

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

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

假设 AB=CA*B=C ,那么要求满足 Ck=ij=kAiBjC_k=\sum\limits_{i\oplus j=k}A_iB_j ,现在给出 A,BA,B ,要求快速求出 CC

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

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

现在考虑推导 KK 进制 FWTFWT 的系数矩阵:

不妨设 n=Ki1n=K^i-1 ,那么有
(fA)[x](fB)[x]=(fC)[x](i=0nfx,iai)(i=0nfx,ibi)=i=0nfx,icifx,k=ij=kfx,ifx,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}
显然光靠这点是不够的,我们需要给 fi,jf_{i,j} 赋予更强的性质:假设当前有 m+1m+1KK 进制位,x=(x0x1x2...xm)Kkx=(x_0x_1x_2...x_m)_Kk ,我们构造fx,y=i=0mfxi,yif_{x,y}=\prod\limits_{i=0}^mf_{x_i,y_i}

x^\hat x 表示 xxKK 进制下的最高位, xˇ\check x 表示 xxKK 进制下的其余位,考虑矩阵乘法的式子:
(fA)[x]=i=0mfx,iai=i=0K1fx^,ij^=ifxˇ,jˇ=i=0K1fx^,i(fAi)[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}\\=&\sum\limits_{i=0}^{K-1}f_{\hat x,i}(f*A_i)[\check x]\end{aligned}

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

考虑之前推出的 ff 元素之间的关系:
fx,k=ij=kfx,ifx,j=[Ki+jk]fx,ifx,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}

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

于是
f=[11111ωk1ωk2ωkk11ωk2ωk4ωk2(k1)1ωkk1ωk2(k1)ωk(k1)(k1)]f1=1k[11111ωk1ωk2ωk(k1)1ωk2ωk4ωk2(k1)1ωk(k1)ωk2(k1)ωk(k1)(k1)] 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]

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

#include<bits/stdc++.h>
#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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!