洛谷 P4831 Scarlet loves WenHuaKe
阿新 • • 發佈:2019-01-05
一題多解
這題首先可以DP
直接三個型別暴力轉移。
\(f[i][j]\)表示無限制填\(i\)行\(j\)列的方案數。
\(f1[i][j]\)表示有一列已經有棋子的方案數。
\(f2[i][j]\)表示有兩列有棋子的方案數。
轉移一下。複雜度\(O(n*(m-n))\)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int M=998244353; const int N=100010; int fac[N],invfac[N]; int f[N]; int n,m; int C(int x,int y){ return (ll)fac[x]*invfac[y]%M*invfac[x-y]%M; } int fp(int x,int y){ int ret=1; for (; y; y>>=1,x=(ll)x*x%M) if (y&1) ret=(ll)ret*x%M; return ret; } int sqr(int x){ return (ll)x*x%M; } int MUL(int x,int y){ return (ll)x*y%M; } int F(int,int); //int debug; int f__k[N][20]; int F1(int n,int m){ //++debug; //cerr<<"F_!"<<n<<" "<<m<<" "<<n-m<<endl; if (n>m) return 0; if (n==0) return 1; if (m<2) return 0; int &ret=f__k[n][m-n]; if (ret) return ret-1; ret=(MUL(MUL(n,m-1),F1(n-1,m-1))+F(n,m-1))%M+1; return ret-1; } int mm[N][20]; int F2(int n,int m){ //getchar(); //cerr<<m-n<<endl; if (n>m) return 0; if (n==0) return 1; if (m<2) return 0; int &ret=mm[n][m-n]; if (ret) return ret-1; //cerr<<"FF"<<n<<" "<<m<<endl; ret=F(n,m-2); //cerr<<"ORG"<<n<<" "<<m<<" "<<ret<<endl; if (n>=2){ (ret+=MUL(2,MUL(MUL(C(n,2),F2(n-2,m-2)),MUL(m-2,m-3))))%=M; (ret+=MUL(2,MUL(MUL(C(n,2),F(n-2,m-3)),m-2)))%=M; } //cerr<<"ORGG"<<n<<" "<<m<<" "<<ret<<endl; if (n>=1) (ret+=MUL(2,MUL(F1(n-1,m-2),MUL(C(n,1),m-2))))%=M; //cerr<<"OGGGG"<<n<<" "<<m<<" "<<ret<<endl; if (n>=1) (ret+=MUL(C(n,1),F(n-1,m-2)))%=M; //cerr<<"FFRET"<<n<<" "<<m<<" "<<ret<<endl; ++ret; //++debug; return ret-1; } int mp[N][20]; int F(int n,int m){ //cerr<<"F"<<n<<" "<<m<<endl; if (n>m) return 0; if (n==0) return 1; if (m<2) return 0; //cerr<<m-n<<endl; int &ret=mp[n][m-n]; if (ret) return ret-1; //cerr<<"F"<<n<<" "<<m<<" "<<mp.size()<<endl; ret=MUL(C(m,2),F2(n-1,m))+1; //if (debug%300==0) cerr<<"FFFF"<<n<<" "<<m<<" "<<ret<<" "<<debug<<endl; return ret-1; } int FF[2010][2010]; int main(){ scanf("%d%d",&n,&m); if (n<=2000){ FF[0][0]=1; for (int i=0; i<=n; ++i){ for (int j=0; j<=m; ++j) if ((i*2-j)%2==0){ int k=(i*2-j)/2; //cerr<<i<<" "<<j<<" "<<k<<" "<<f[i][j][k]<<endl; int z0=m-k-j,c=FF[i][j]; //cerr<<i<<" "<<j<<" "<<z0<<endl; if (j>=1&&z0>=1) (FF[i+1][j]+=(ll)j*z0%M*c%M)%=M; if (z0>=2) (FF[i+1][j+2]+=((ll)z0*(z0-1)/2)%M*c%M)%=M; if (j>=2) (FF[i+1][j-2]+=((ll)j*(j-1)/2)%M*c%M)%=M; } } int ans=0; for (int i=0; i<=m; ++i){ //cerr<<i<<" "<<f[n][i]<<endl; (ans+=FF[n][i])%=M; } cout<<ans; return 0; } fac[0]=1; for (int i=1; i<=m; ++i) fac[i]=(ll)fac[i-1]*i%M; invfac[m]=fp(fac[m],M-2); for (int i=m-1; i>=0; --i) invfac[i]=(ll)invfac[i+1]*(i+1)%M; //cerr<<invfac[2]<<" "<<invfac[3]<<endl; cout<<F(n,m)<<endl; //cerr<<debug<<endl; }
還可以用題解的反演,沒有實現過。