UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强 【分治乘法】
题目分析:
首先不难注意到式子就是异或卷积,所以考虑用分治乘法推出优化方法。
我们把一个整体$f$拆成$f-,f\pm,f+$,然后另一个拆成$g-,g\pm,g+$.这样做的好处是能更清楚的分析问题。下面我们下宽油(大雾)。
发现三个部分要求的式子是在两者相乘中选不同的三个,所以我们发现三个部分中每取一个有相同。这样我们聚焦到$--,-\pm,-+$三个东西。观察二进制FWT,可以假想它们要使用到三次单位根。这样只需要把三个根错开排列就行了。
做分治乘法的时候注意把虚部的$I$记做$\sqrt{3}i$.
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1020000; 5 6 struct cn{int rl,vir;}e[3]; // vir's real meaning is vir*sqrt(3) 7 8 int iv2,iv3; 9 int m,n,t,p,phi; 10 int b3[20],b[20][20]; 11 cn val[maxn],f[maxn]; 12 13 int W[maxn],L[maxn]; 14 15 cn operator +(const cn& alpha,const cn& beta){ 16 cn ans = (cn){alpha.rl+beta.rl,alpha.vir+beta.vir}; 17 if(ans.rl >= p) ans.rl -= p; 18 if(ans.vir >= p) ans.vir -= p; 19 return ans; 20 } 21 cn operator *(const cn& alpha,const cn& beta){ 22 cn ans = (cn){0,0}; 23 ans.rl = (1ll*alpha.rl*beta.rl-3ll*alpha.vir*beta.vir)%p; 24 ans.rl += p; if(ans.rl >= p) ans.rl -= p; 25 ans.vir = (1ll*alpha.vir*beta.rl+1ll*alpha.rl*beta.vir)%p; 26 return ans; 27 } 28 cn operator *(const cn& alpha,const int& beta){ 29 cn ans=alpha;ans.rl=(1ll*ans.rl*beta)%p;ans.vir=(1ll*ans.vir*beta)%p; 30 return ans; 31 } 32 33 cn fast_pow(cn now,int pw){ 34 int bit = 1;cn ans = (cn){1,0},dt = now; 35 while(bit <= pw){ 36 if(bit & pw) ans = ans*dt; 37 bit<<=1;dt = dt*dt; 38 } 39 return ans; 40 } 41 int fast_pow(int now,int pw){ 42 int bit = 1,ans = 1,dt = now; 43 while(bit <= pw){ 44 if(bit & pw) ans = (1ll*ans*dt)%p; 45 bit<<=1;dt = (1ll*dt*dt)%p; 46 } 47 return ans; 48 } 49 50 void read(){ 51 scanf("%d%d%d",&m,&t,&p); 52 b3[0] = 1; for(int i=1;i<=m;i++) b3[i] = b3[i-1]*3; 53 n = b3[m]; 54 for(int i=0;i<n;i++) scanf("%d",&f[i].rl); 55 for(int i=0;i<=m;i++){ 56 for(int j=0;i+j<=m;j++){ 57 scanf("%d",&b[i][j]); 58 } 59 } 60 val[0].rl = b[0][0]; 61 for(int i=1;i<n;i++){ 62 W[i] = W[i/3],L[i] = L[i/3]; 63 if(i % 3 == 2) L[i]++; 64 if(i % 3 == 1) W[i]++; 65 val[i].rl = b[W[i]][L[i]]; 66 } 67 } 68 69 void multi(int l,int r){ 70 if(l == r-1){ 71 f[l] = f[l]*fast_pow(val[l],t); 72 }else{ 73 int l1 = l+(r-l)/3,l2 = l+2*(r-l)/3,d = l2-l1; 74 for(int i=0;i<d;i++){ 75 cn p1 = f[l+i],p2 = f[l1+i],p3 = f[l2+i]; 76 f[l+i] = p1+p2+p3; 77 f[l1+i] = p1+e[1]*p2+e[2]*p3;f[l2+i] = p1+e[2]*p2+e[1]*p3; 78 p1 = val[l+i],p2 = val[l1+i],p3 = val[l2+i]; 79 val[l+i] = p1+p2+p3; 80 val[l1+i] = p1+e[1]*p2+e[2]*p3;val[l2+i] = p1+e[2]*p2+e[1]*p3; 81 } 82 multi(l,l1); multi(l1,l2); multi(l2,r); 83 for(int i=0;i<d;i++){ 84 cn p1 = f[l+i],p2 = f[l1+i],p3 = f[l2+i]; 85 f[l+i] = p1+p2+p3; 86 f[l1+i] = p1+e[2]*p2+e[1]*p3;f[l2+i] = p1+e[1]*p2+e[2]*p3; 87 f[l+i]=f[l+i]*iv3;f[l1+i]=f[l1+i]*iv3;f[l2+i]=f[l2+i]*iv3; 88 } 89 } 90 } 91 92 void init(){ 93 phi = p;int z = p; 94 for(int i=2;i*i<=p;i++){ 95 if(p % i == 0){ 96 while(p%i == 0) p /= i; 97 phi = (phi/i)*(i-1); 98 } 99 } 100 if(p != 1) phi = (phi/p)*(p-1); p =z; 101 iv2 = fast_pow(2,phi-1); iv3 = fast_pow(3,phi-1); 102 e[0] = (cn){1,0}; e[1] = (cn){p-iv2,iv2}; e[2] = (cn){p-iv2,p-iv2}; 103 } 104 105 void work(){ 106 multi(0,n);//[0,n) 107 for(int i=0;i<n;i++) printf("%d\n",f[i].rl); 108 } 109 110 int main(){ 111 read(); 112 init(); 113 work(); 114 return 0; 115 }