一题多解
这题首先可以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;
}
还可以用题解的反演,没有实现过。