1. 程式人生 > >Luogu P2051 [AHOI2009]中國象棋 | dp

Luogu P2051 [AHOI2009]中國象棋 | dp

題目 為知 復雜 ons soft tps 代碼 www ont

題目鏈接

30分:

爆搜。

50分:

可以發現,每行和每列最多都只能放兩個象棋,考慮三進制狀壓dp,表示出每列放了多少個象棋(只能是0個,1個或2個),從上往下一行一行地處理即可。如果列數過於大的話,交換行數和列數再處理就行了,因為在50%的數據中,行數和列數中至少是有一個不超過8的。

100分:

通過思考,可以發現象棋的詳細位置是不用知道的,我們只需知道有多少列沒放象棋,有多少列放了一個象棋,有多少列放了兩個象棋就行了。又因為知道了放了一個象棋的列數和放了兩個象棋的列數就可以求出沒放象棋的列數,所以我們只需記錄後兩個量即可。這樣我們的狀態就出來了:f[i][j][k]表示前i行,有j列放了一個象棋,k列放了兩個象棋的擺放方案數,其中,沒放象棋的列數就為(m-j-k)。

轉移就很簡單了,分幾類討論就可,算一算就出來了。

時間復雜度:O(nm2)。

代碼:

#include<iostream>
#include<cstdio>
    using namespace std;
    const long long c=9999973;
    long long f[105][105][105];
int main()
{
    int n=0;
    long long m=0;
    scanf("%d%lld",&n,&m);
    f[0][0][0]=1;//初始化 
    for(int
i=0;i<=n-1;i++) for(long long j=0;j<=m;j++) for(long long k=0;j+k<=m;k++) { //不放象棋 f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%c; //放一個象棋,放在沒有任何象棋的列上 f[i+1][j+1][k]=(f[i+1][j+1][k]+((m-j-k)*f[i][j][k])%c)%c;
//放一個象棋,放在有一個象棋的列上 if(j>=1) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+(j*f[i][j][k])%c)%c; //放兩個象棋,都放在沒有任何象棋的列上 f[i+1][j+2][k]=(f[i+1][j+2][k]+((m-j-k)*(m-j-k-1)/2*f[i][j][k])%c)%c; //放兩個象棋,都放在有一個象棋的列上 if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+(j*(j-1)/2*f[i][j][k])%c)%c; //放兩個象棋,一個放在沒有任何象棋的列上,一個放在有一個象棋的列上 if(j>=1) f[i+1][j+1-1][k+1]=(f[i+1][j+1-1][k+1]+((m-j-k)*j*f[i][j][k])%c)%c; } long long ans=0; for(int i=0;i<=m;i++) for(int j=0;i+j<=m;j++) ans=(ans+f[n][i][j])%c;//統計答案 printf("%lld",ans); return 0; }

Luogu P2051 [AHOI2009]中國象棋 | dp