考虑我们现在对两个幂级数 A , B A,B A,B 定义运算 ∗ * ∗ :
假设 A ∗ B = C A*B=C A∗B=C ,那么要求满足 C k = ∑ i ⊕ j = k A i B j C_k=\sum\limits_{i\oplus j=k}A_iB_j Ck=i⊕j=k∑AiBj ,现在给出 A , B A,B A,B ,要求快速求出 C C C 。
于是我们考虑构造矩阵 f f f 满足 ( f ∗ A ) ∗ ( f ∗ B ) = ( f ∗ C ) (f*A)*(f*B)=(f*C) (f∗A)∗(f∗B)=(f∗C) 且 f f f 可逆,那么现在只需快速求出 f ∗ A , f ∗ B , f − 1 ( f ∗ C ) f*A,f*B,f^{-1}(f*C) f∗A,f∗B,f−1(f∗C)即可。
不难发现当 ⊕ \oplus ⊕ 为加法时我们的 f f f 即是系数表示法到点值表示法的转移矩阵。
不妨设 n = K i − 1 n=K^i-1 n=Ki−1 ,那么有
( 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} (f∗A)[x]∗(f∗B)[x]=(i=0∑nfx,iai)(i=0∑nfx,ibi)=fx,k=(f∗C)[x]i=0∑nfx,icii⊕j=k∑fx,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=0∏mfxi,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} (f∗A)[x]===i=0∑mfx,iaii=0∑K−1fx^,ij^=i∑fxˇ,jˇaji=0∑K−1fx^,i(f∗Ai)[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==i⊕j=k∑fx,ifx,j[K∣i+j−k]∑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=⎣⎢⎢⎢⎢⎡111⋯11ωk1ωk2⋯ωkk−11ωk2ωk4⋯ωk2(k−1)⋯⋯⋯⋯⋯1ωkk−1ωk2(k−1)⋯ωk(k−1)(k−1)⎦⎥⎥⎥⎥⎤f−1=k1⎣⎢⎢⎢⎢⎢⎡111⋯11ω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)⎦⎥⎥⎥⎥⎥⎤
例题:[清华集训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;
}