[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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM