[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$变为然后拆解即可。

代码: 

  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 }
codeforces901E

猜你喜欢

转载自www.cnblogs.com/Troywar/p/8946940.html
今日推荐