洛谷.2051.[AHOI2009]中國象棋(DP)
阿新 • • 發佈:2018-02-12
sca div mar scan log 註意 gpo print 三種
題目鏈接
/*
每行每列不能超過2個棋子,求方案數
前面行對後面行的影響只有 放了0個、1個、2個 棋子的列數,與排列方式無關
所以設f[i][j][k]表示前i行,放了0個棋子的有j列,放了1個棋子的有k列,則放了2個棋子的為(m-j-k)列
則放棋子一共可分為6種情況
不放棋子:1.f[i+1][j+2][k] += f[i][j][k]
放一個棋子:2.放在沒有棋子的那一列 f[i+1][j-1][k+1] += f[i][j][k]*j
3.放在有棋子的那一列 f[i+1][j][k-1] += f[i][j][k]*k
放兩個棋子:4.都放在沒有棋子的兩列 f[i+1][j-2][k+2] += f[i][j][k]*C(j,2)
5.都放在有一個棋子的兩列 f[i+1][j][k-2] += f[i][j][k]*C(k,2)
6.一個放在沒有棋子的一列,一個放在有一個棋子的一列 f[i+1][j-1][k] += f[i][j][k]*j*k
或用f[i][j][k]表示第i行,放了1個棋子的有j列,放了2個棋子的有k列,沒放棋子的有(m-j-k)列
*/
#include<cstdio>
using namespace std;
const int N=105,mod=9999973;
int n,m;
long long f[N][N][N];//long long!
inline int C(int n)//C(n,2)
{
return n*(n-1)>>1;
}
//inline void Add(int /&n,int b)
//{
// n+=b;
// n-= n>=mod?mod:0;
//}
int main()
{
scanf("%d%d",&n,&m);
f[0][m][0]=1;
// f[0][0][0]=1;
for(int i=0;i<n;++i)
for(int j=0;j<=m;++j)
for(int k=0;k+j<=m;++k)
if (f[i][j][k])//0是無意義的
{
// f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;
// if(m-k-j>=1) f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-k-j))%mod;
// if(j) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j)%mod;
// if(m-k-j>=2) f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*C(m-k-j))%mod;
// if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*C(j))%mod;
// if(m-k-j>=1 && j>=1) f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-k-j)*j)%mod;
//註意 && j>=1!雖然能得到一個j,但條件中必須有一個j
f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;//不放不會增加不放棋子的列數!
if(j>=1) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j%mod)%mod;
if(k>=1) f[i+1][j][k-1]=(f[i+1][j][k-1]+f[i][j][k]*k%mod)%mod;
if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*C(j)%mod)%mod;
if(k>=2) f[i+1][j][k-2]=(f[i+1][j][k-2]+f[i][j][k]*C(k)%mod)%mod;
if(j>=1 && k>=1) f[i+1][j-1][k]=(f[i+1][j-1][k]+f[i][j][k]*j*k%mod)%mod;
//跑得慢。。懵逼
}
long long res=0;
for(int i=0;i<=m;++i)//枚舉不放的列
for(int j=0;i+j<=m;++j)//枚舉放一個的列
res=(res+f[n][i][j])%mod;//兩種確定,第三種列也確定
printf("%lld",res);
return 0;
}
洛谷.2051.[AHOI2009]中國象棋(DP)