1. 程式人生 > >洛谷.2051.[AHOI2009]中國象棋(DP)

洛谷.2051.[AHOI2009]中國象棋(DP)

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)