[codeforces 901E] Cyclic Cipher 循环卷积-Bluestein's Algorithm
题目大意:
给两个数列${B_i}、{C_i}$,长度均为$n$,且${B_i}$循环移位线性无关,即不存在一组系数${X_i}$使得对于所有的$k$均有$\sum_{i=0}^{n-1} X_i B_{k-i \mod n} =0$。
已知$C$是由$B$与$A$构造得到:
(搬原图)。
求所有合法的$A$序列。
题解:
首先把式子稍加化简会得到:
显然是个差分式,然后就会得到以下两种结果(以下$B_{i}$均为$B_{i\mod n}$):
问题是,这两个式子都是对的吗?
显然不是。
我们考虑题目中说的${B_i}$为循环移位线性无关,但是$\Delta B_i=B_{i+1}-B_{i}$构成的${\Delta B_{i}}$我们是不知道它是否是线性无关的,如果是线性无关,那么它是正确的,反之,我们会知道必然存在一组${X_i}$使得若${A}$有解,则有无穷解,但是回带是错误的。
但是二式我们如果可以求解可知$\Delta A_i=A_{i+1}-A{i}$是有唯一解的,然后考虑回带求$A_0$我们就可以得到最多两个解。
所以本题就变成了求:
设$B'_i=B_{-i}$,即:
即,问题变为求出$\Delta C$的点值然后除去$B'_{*Z/n}$的点值再除去$-2$我们再由$\Delta A$的点值求出其系数即可。
当然,我们可以知道$\Delta A$的系数小于$2e3$,所以我们防止卡精使用$NTT$。
由于并不知道$B'_{*Z/n}$的长度,所以不能裸上,需要使用Bluestein's Algorithm。
这个东西网上几乎没有讲解,好像毛爷爷的《再探》里面有说?
具体就是:
这样就可以使用一次卷积来求$B'$的点值了。($NTT$并不能直接拆成上面的形式,因为数论变换是没法消去下面除的那个2)
所以将$ik$变为然后拆解即可。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "bits/stdc++.h" 2 3 typedef long long ll; 4 5 inline int read() { 6 int s=0,k=1;char ch=getchar(); 7 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); 8 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); 9 return s*k; 10 } 11 12 const int N=6e5+10; 13 14 ll mod,g,w[2][N],W[2][N]; 15 16 inline ll Mult ( ll a,ll b ) { 17 return ( a*b - (ll)( (long double) a*b/mod )*mod + mod )% mod; 18 } 19 20 inline ll powmod ( ll a, ll b ) { 21 ll ret=1; 22 while (b) { 23 if (b&1) ret=Mult ( ret, a ); 24 b>>=1,a=Mult ( a, a); 25 }return ret; 26 } 27 28 inline ll gcd ( ll a,ll b ) { return b?gcd(b,a%b) : a; } 29 30 int n,m; 31 32 inline void Get_mod () { 33 for (m=1; (m<=2*n) ;m<<=1 ); 34 ll lcm =1ll* n*m /gcd (n,m); 35 mod = lcm + 1; 36 while ( mod < 1e5 ) mod += lcm; 37 while (1) { 38 int flag=true; 39 for (int i=2;1ll*i*i<=mod;++i) if (mod%i==0) {flag=false;break;} 40 if (flag) break; 41 mod+=lcm; 42 } 43 for (g=2;;++g) { 44 int flag=true; 45 for (int i=2;1ll*i*i<=mod;++i) if ((mod-1)%i==0){ 46 if (powmod(g,i)==1) {flag=false;break;} 47 if (powmod(g,(mod-1)/i)==1) {flag=false;break;} 48 } 49 if (flag) break; 50 } 51 } 52 53 inline void Get_wn(){ 54 ll w0=powmod(g,(mod-1)/m); 55 w[0][0]=w[1][0]=1; 56 int i; 57 for (i=1;i<m;++i) w[0][i]=Mult(w[0][i-1],w0); 58 for (i=1;i<m;++i) w[1][i]=w[0][m-i]; 59 w0=powmod(g,(mod-1)/n); 60 W[0][0]=W[1][0]=1; 61 for (i=1;i<n;++i) W[0][i]=Mult(W[0][i-1],w0); 62 for (i=1;i<n;++i) W[1][i]=W[0][n-i]; 63 } 64 65 inline void NTT(ll *a,int n,int f) { 66 register int i,j,k,l,t; 67 for (i=j=0;i^n;++i) { 68 if (i>j) std::swap(a[i],a[j]); 69 for (k=n>>1;(j^=k)<k;k>>=1); 70 } 71 for (i=1;i<n;i<<=1) 72 for (j=0,t=n/(i<<1);j<n;j+=i<<1) 73 for (k=l=0;k<i;++k , l+=t ) { 74 ll x=a[j+k],y=Mult(a[i+j+k],w[f][l]); 75 a[j+k]=x+y; 76 a[i+j+k]=x-y; 77 if (a[j+k]>=mod) a[j+k]-=mod; 78 if (a[i+j+k]<0) a[i+j+k]+=mod; 79 } 80 if (f ) { 81 ll rev=powmod ( n,mod-2 ); 82 for (i=0;i<n;++i) a[i]=Mult(a[i],rev); 83 } 84 } 85 86 ll Y[N]; 87 88 inline void pre_Bluestein(int f) { 89 int i; 90 for (i=0;i<2*n;++i) Y[2*n-1-i]=W[f][1ll*i*(i-1)/2%n]; 91 for (i=2*n;i<m;++i) Y[i]=0; 92 NTT(Y,m,0); 93 } 94 95 inline void Bluestein(ll *a,int f){ 96 static ll X[N]; 97 register int i; 98 for (i=0;i<n;++i) X[i]=Mult(a[i],W[f][ (n-1ll*i*(i-1)/2%n)%n ]); 99 for (i=n;i<m;++i) X[i]=0; 100 NTT(X,m,0); 101 for (i=0;i<m;++i) X[i]=Mult(X[i],Y[i]); 102 NTT(X,m,1); 103 for (i=0;i<n;++i) 104 a[i]=Mult (X[2*n-1-i],W[f][(n-1ll*i*(i-1)/2%n)%n ]); 105 if (f) { 106 ll rev=powmod(n,mod-2); 107 for (i=0;i<n;++i) a[i]=Mult(a[i],rev); 108 } 109 } 110 111 int b[N],c[N]; 112 ll rev_b[N],delta_c[N],delta_a[N],a[N]; 113 114 int main() { 115 //freopen(".in","r",stdin); 116 n = read(); 117 register int i; 118 for (i=0;i<n;++i) b[i]=read(); 119 for (i=0;i<n;++i) c[i]=read(); 120 Get_mod(); 121 Get_wn(); 122 for (i=0;i<n;++i) rev_b[i]=b[i]; 123 std::reverse(rev_b+1,rev_b+n); 124 ll inv_2=powmod(mod-2,mod-2); 125 for (i=0;i<n;++i) delta_c[i]=Mult ( ( c[(i+1)%n]-c[i] + mod )%mod , inv_2 ); 126 pre_Bluestein(0); 127 Bluestein(rev_b,0); 128 Bluestein(delta_c,0); 129 for (i=0;i<n;++i) delta_a[i]=Mult ( delta_c[i] , powmod (rev_b[i],mod-2) ); 130 pre_Bluestein(1); 131 Bluestein(delta_a,1); 132 for (i=0;i<n;++i) { 133 ll v=(delta_a[i]<mod-delta_a[i])?delta_a[i]:delta_a[i]-mod; 134 if (abs(v)>20000) return puts("0"),0; 135 a[i]=v; 136 } 137 ll _c=-c[0],_a=0,_b=0,sum=0; 138 for (i=0;i<n;++i) { 139 ++_a; 140 _b+=2*(sum-b[i]); 141 _c+=(sum-b[i])*(sum-b[i]); 142 sum+=a[i]; 143 } 144 if (sum!=0) { 145 puts("0"); 146 return 0; 147 } 148 std::set<ll> ans; 149 if (_b*_b-4*_a*_c>=0){ 150 ll s=ll(sqrt(_b*_b-4*_a*_c) + 0.5); 151 if (s*s!=_b*_b-4*_a*_c) return puts("0"),0; 152 if ((-_b+s)%(2*_a)==0) ans.insert((-_b+s)/(2*_a)); 153 if ((-_b-s)%(2*_a)==0) ans.insert((-_b-s)/(2*_a)); 154 } 155 std::set<ll>::iterator it; 156 printf("%d\n",ans.size()); 157 for (it=ans.begin();it!=ans.end();++it) { 158 ll now=*it; 159 for (i=0;i<n;++i){ 160 printf("%lld ",now); 161 now+=a[i]; 162 } 163 puts(""); 164 } 165 }