YY模拟:棋盘(FFT)

题意:
给定nm的棋盘(n3,m1e5),给定k,问有多少种染色方案使得最终棋盘的黑色联通块恰好k(mod998244353)

题解:
n=3,我们可以状压DP,记fi,j,k表示DP到i列,状态为j,联通块为k的方案数。

显然我们有O(mk92)的做法,不过我们可以用生成函数+矩阵乘法来优化。

最终答案是nm2次多项式,我们带入这么多个点来求点值做DFT,每次点值就可以直接矩乘递推了,时间复杂度为O(nm293).

最后做FFT,总时间复杂度为O(nm2(93+lognm2)),注意卡常。

(其实不用卡常,真正的有效状态只有7种,不过太懒就不写了。。)

#include <bits/stdc++.h>
using namespace std; 
typedef unsigned long long ULL;

const int N=233333*2, mod=998244353, G=3;
const ULL LIM=(ULLONG_MAX/mod-mod)*mod;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (ULL)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
inline int inv(int a) {return power(a,mod-2);}
#define P(a,b) power(a,b)
int n,m,k,K,L,pos[N],W[N],yc[N];
inline void dft(int *a) {
    for(int i=1;i<k;i++) pos[i]=(i&1) ? ((pos[i>>1]>>1)^(k>>1)) : (pos[i>>1]>>1);
    for(int i=1;i<k;i++) if(pos[i]>i) swap(a[pos[i]],a[i]);
    for(int bl=1;bl<k;bl<<=1) {
        int tl=bl<<1, wn=power(G,(mod-1)/tl);
        W[0]=1; for(int i=1;i<bl;i++) W[i]=mul(W[i-1],wn);
        for(int bg=0;bg<k;bg+=tl)
            for(int j=0;j<bl;j++) {
                int &t1=a[bg+j], &t2=a[bg+j+bl], t=mul(t2,W[j]);
                t2=dec(t1,t); t1=add(t1,t);
            }
    }
}
struct matrix {
    ULL a[10][10];
    matrix() {}
    matrix(int t) {
        memset(a,0,sizeof(a));
        for(int i=0;i<=L;i++) a[i][i]=t;
    }
    friend inline matrix operator *(const matrix &a,const matrix &b) {
        matrix c(0);
        for(int i=0;i<=L;i++)
            for(int k=0;k<=L;k++) if(a.a[i][k])
                for(int j=0;j<=L;j++)
                    if((c.a[i][j]+=a.a[i][k]*b.a[k][j])>=LIM) c.a[i][j]%=mod;
        for(int i=0;i<=L;i++)
            for(int j=0;j<=L;j++)
                if(c.a[i][j]>=mod) c.a[i][j]%=mod;
        return c;
    }
    friend inline matrix operator ^(matrix a,int b) {
        matrix rs(1);
        for(;b;b>>=1,a=a*a) if(b&1) rs=rs*a;
        return rs;
    }
}pw;
#define opt() for(int i=0;i<=L;++i)\
                  for(int j=0;j<=L;++j)\
                       pw.a[i][j]=tp[i][j]
inline int getval(int w) {
    if(L==1) {
        int tp[2][2]={ {1,w},
                       {1,1} }; 
        opt();
    } else if(L==3) {
        int tp[4][4]={ {1,w,w,w},
                       {1,1,w,1},
                       {1,w,1,1},
                       {1,1,1,1} };
        opt();
    } else {
        int tp[9][9]={ {1,w,w,w,w,P(w,2),w,w,0},
                       {1,1,w,1,w,w,w,1,0},
                       {1,w,1,1,w,P(w,2),1,1,0},
                       {1,1,1,1,w,w,1,1,0},
                       {1,w,w,w,1,w,1,1,0},
                       {1,1,w,1,1,1,1,inv(w),0}, 
                       {1,w,1,1,1,w,1,1,0}, 
                       {1,1,1,1,1,0,1,1,1}, 
                       {1,1,w,1,1,0,1,1,1}, };
        opt();
    }
    matrix A(0); 
    A.a[0][0]=1;
    A=A*(pw^m);
    int ans=0;
    for(int i=0;i<=L;++i) ans=add(ans,A.a[0][i]);
    return ans;
}
inline int solve() {
    for(k=1; k<=(n*m)/2+2;k<<=1);
    int wn=power(G,(mod-1)/k), w=1;
    for(int i=0;i<k;i++) 
        yc[i]=getval(w), w=mul(w,wn);
    dft(yc); reverse(yc+1,yc+k); 
    const int iv=power(k,mod-2);
    return mul(yc[K],iv);
}
int main() {
    cin>>n>>m>>K;
    L=((n==1) ? 1 : ((n==2) ? 3 : 8));
    cout<<solve();
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/79965741
个人分类: ntt、fft OGF
上一篇YY模拟:跳蚤(分块)
下一篇BJ模拟:Circle Of Stone(KMP)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭