zoukankan      html  css  js  c++  java
  • [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_{imod 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
    ",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
  • 相关阅读:
    ThinkPHP实现定时任务
    VUE 父子组件之间通信传值 props和 $emit,事件触发传值ref,以及兄弟组件之间的通信传值 eventBus
    JS链接转换为二维码
    VUE 动态切换列表active样式
    微信内置浏览器video标签自动全屏的问题
    JS监听video视频播放时间
    JS数据统计表 highcharts.js的运用
    JS 自动返回每个月的天数
    JS 一键复制插件应用 和 原生实现
    JS enter键一键登录
  • 原文地址:https://www.cnblogs.com/Troywar/p/8946940.html
Copyright © 2011-2022 走看看