zoukankan      html  css  js  c++  java
  • 「HNOI 2019」白兔之舞

    一道清真的数论题

    LOJ #3058

    Luogu P5293


    题解

    考虑$ n=1$的时候怎么做

    设$ s$为转移的方案数

    设答案多项式为$sumlimits_{i=0}^L (sx)^iinom{L}{i}=(sx+1)^L$

    答案相当于这个多项式模$ k$的各项系数的和

    发现这和LJJ学二项式定理几乎一模一样

    我上一题的题解

    然而直接搞是$ k^2$的,无法直接通过本题

    以下都用$ w$表示$ k$次单位根

    设$ F_i$为次数模$ k$为$ i$的项的系数和

    单位根反演一下得到$F(i)=sumlimits_{j=0}^{k-1}w^{-ij}(sw^j+1)^L$

    组合数有个非常优美的性质

    $$ij=inom{i+j}{2}-inom{i}{2}-inom{j}{2}$$

    推波式子

    $$
    egin{aligned}
    F(i)&=sum_{j=0}^{k-1}w^{-ij}(sw^j+1)^L\
    &=sum_{j=0}^{k-1}w^{inom{i}{2}+inom{j}{2}-inom{i+j}{2}}(sw^j+1)^L\
    &=w^inom{i}{2}sum_{j=0}^{k-1}w^{-inom{i+j}{2}}w^inom{j}{2}(sw^j+1)^L\
    end{aligned}
    $$

    发现这是一个差卷积的形式

    扔一个$ MTT$上去就能拿那$ 40$分了

    考虑$ n>1$的情况

    相当于把$ s$从一个数变成了矩阵,把$ 1$变成单位矩阵

    $ (sw^j+1)^L$这个矩阵我们只需要关注一个位置上的值

    因此可以乘出来然后取[x][y]这个位置上的数即可

    这样就可以通过此题

    复杂度:大常数单 $log$


    代码

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define rt register int
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0;char zf=1;char ch=getchar();
        while(ch!='-'&&!isdigit(ch))ch=getchar();
        if(ch=='-')zf=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int k,m,n,x,y,cnt,p,L;
    int w[65539],val[65539];
    int f[65539],g[65539],F[65539];
    int ksm(int x,int y=p-2){
        int ans=1;
        for(;y;y>>=1,x=1ll*x*x%p)if(y&1)ans=1ll*ans*x%p;
        return ans;
    }
    struct mat{
        ll a[3][3];    
        void print(){
            for(rt i=0;i<n;i++)for(rt j=0;j<n;j++)cout<<a[i][j]<<" 
    "[j==n-1];
        }
        inline mat operator*(const mat s)const{
            mat ret={0};
            for(rt i=0;i<n;i++)
            for(rt k=0;k<n;k++)
            for(rt j=0;j<n;j++)
            (ret.a[i][j]+=a[i][k]*s.a[k][j]);
            for(rt i=0;i<n;i++)for(rt j=0;j<n;j++)ret.a[i][j]%=p;
            return ret;
        }
        mat operator*(const int s)const{
            mat ret;
            for(rt i=0;i<n;i++)
            for(rt j=0;j<n;j++)
            ret.a[i][j]=a[i][j]*s%p;
            return ret;
        }
        mat operator+(const mat s)const{
            mat ret;memset(ret.a,0,sizeof(ret.a));
            for(rt i=0;i<n;i++)
            for(rt j=0;j<n;j++)
            ret.a[i][j]=(a[i][j]+s.a[i][j])%p;
            return ret;
        }
    
    }I,zy;
    mat ksm(mat x,int y){
        mat ans=I;
        for(;y;y>>=1,x=x*x)if(y&1)ans=ans*x;
        return ans;
    }
    int V(int x){
        return 1ll*x*(x-1)/2%k;
    }
    const double PI=acos(-1.0);
    struct cp{
        double x,y;
        cp operator +(const cp &s)const{return {x+s.x,y+s.y};}
        cp operator -(const cp &s)const{return {x-s.x,y-s.y};}
        cp operator *(const cp &s)const{return {x*s.x-y*s.y,x*s.y+y*s.x};}
    }W[18][1<<17],A[270010],B[270010],C[270010],D[270010];
    int R[270010];
    void FFT(const int n,cp *A){
        for(rt i=0;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]);
        for(rt j=0;j<n;j+=2){
            const cp x=A[j],y=A[j+1];
            A[j]=x+y,A[j+1]=x-y;
        }
        for(rt i=2,s=1;i<n;i<<=1,s++)
        for(rt j=0;j<n;j+=i<<1)
        for(rt k=0;k<i;k+=2){
            cp x=A[j+k],y=W[s][k]*A[i+j+k];
            A[j+k]=x+y;A[i+j+k]=x-y;
            x=A[j+k+1],y=W[s][k+1]*A[i+j+k+1];
            A[j+k+1]=x+y;A[i+j+k+1]=x-y;
        }
    }
    int yg(int n){
        for(rt i=1;i<=n;i++){
            for(rt j=2;j*j<=n;j++)if((n-1)%j==0)
            if(ksm(i,(n-1)/j)==1)goto end;
            return i;end:;
        }
    }
    void subtask(){
        w[0]=1;w[1]=ksm(yg(p),(p-1)/k);
        for(rt i=2;i<k;i++)w[i]=1ll*w[i-1]*w[1]%p;mat s=zy;
        for(rt i=0;i<k;i++){
            g[i]=ksm(s*w[i]+I,L).a[x-1][y-1]*w[V(i)]%p;
        }    
        for(rt i=0;i<k+k;i++)f[i]=w[(k-V(i))%k];
        for(rt i=0;i<k/2;i++)swap(g[i],g[k-i]);
    
        n=k+k-1;m=k;
        int lim=1;while(lim<=n+m)lim<<=1;
        for(rt i=0;(1<<i)<lim;i++){
            W[i][0]={1,0};
            W[i][1]={cos(PI/(1<<i)),sin(PI/(1<<i))};   
            for(rt j=2;j<1<<i;j++)
            if(j%32==0)W[i][j]={cos(PI*j/(1<<i)),sin(PI*j/(1<<i))};
            else W[i][j]=W[i][j-1]*W[i][1];
        }
     
        for(rt i=0;i<=n;i++){
            A[i].x=f[i]>>15;
            A[i].y=f[i]&32767;
        }
        for(rt i=0;i<=m;i++){
            B[i].x=g[i]>>15;
            B[i].y=g[i]&32767;
        }
        for(rt i=1;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
        FFT(lim,A);FFT(lim,B);
        for(rt i=0;i<lim;i++){
            const int pl=(lim-1)&(lim-i);
            const cp ca={A[pl].x,-A[pl].y},cb={B[pl].x,-B[pl].y};
            const cp a=(A[i]+ca)*(cp){0.5,0},b=(A[i]-ca)*(cp){0,-0.5},
                      c=(B[i]+cb)*(cp){0.5,0},d=(B[i]-cb)*(cp){0,-0.5};
            C[pl]=a*c+a*d*(cp){0,1};D[pl]=b*c+b*d*(cp){0,1};
        }
        FFT(lim,C);FFT(lim,D);
        for(rt i=k;i<k+k;i++){
            const int vv=1ll*w[V(i-k)]*ksm(k,p-2)%p;
            ll a=C[i].x/lim+0.5,b=C[i].y/lim+0.5,c=D[i].x/lim+0.5,d=D[i].y/lim+0.5;
            a=((a%p)<<30)+(((b+c)%p)<<15)+d;a=(a%p+p)%p;
            writeln(1ll*a*vv%p);
        }
        exit(0);
    }
    int jc[100010],njc[100010],inv[100010],ff[100010][3],ans[100010];
    int c(int x,int y){
        return 1ll*jc[x]*njc[y]%p*njc[x-y]%p;
    }
    void bl(){
        for(rt i=0;i<2;i++)jc[i]=njc[i]=inv[i]=1;
        for(rt i=2;i<=L;i++){
            jc[i]=1ll*jc[i-1]*i%p;
            inv[i]=1ll*inv[p%i]*(p-p/i)%p;
            njc[i]=1ll*njc[i-1]*inv[i]%p;
        }
        ff[0][x-1]=1;if(x==y)ans[0]=1;
        for(rt i=1;i<=L;i++)
        for(rt j=0;j<n;j++){
            for(rt k=0;k<n;k++)
            (ff[i][j]+=1ll*zy.a[k][j]*ff[i-1][k]%p)%=p;
            if(j==y-1)(ans[i%k]+=1ll*ff[i][j]*c(L,i)%p)%=p;
        }
        for(rt i=0;i<k;i++)writeln(ans[i]);exit(0);
    }
    int main(){
        cin>>n>>k>>L>>x>>y>>p;
        for(rt i=0;i<n;i++)
        for(rt j=0;j<n;j++)
        cin>>zy.a[i][j];
        if(L<=100000)bl();
        for(rt i=0;i<n;i++)I.a[i][i]=1;
        subtask();
        return 0;
    }
  • 相关阅读:
    Vim怎么批量处理文件将tab变为space
    猫狗模型代码
    googLeNet网络
    Alex网络
    搭建FTP服务器
    除非Microsoft FTP 服务(FTPSVC)正在运行,否则无法启动FTP站点。服务目前已停止
    FTP文件夹打开错误,Windows无法访问此文件夹
    win7系统中ftp服务器搭建方法(多图)
    windows server 2008服务器IIS绑定阿里云域名
    URL Routing
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10672461.html
Copyright © 2011-2022 走看看