[BZOJ 1801] Chess

Link:

BZOJ 1801 传送门

Solution:

一眼看过去又像是状压$dp$的经典模型……

但此题$n,m\le 100$ ,直接跑状压只有50分

此时要发现这道题的特点:每行/列不能放置超过2个

既然每一列只可能有 不选/选1个/选2个 这三种状态,直接记录这三种状态的个数即可

于是设$dp[i][j][k]$为到第$i$行时,有$j$列放置了1个,有$k$列放置了2个的方案数

接下来分五种情况递推就行了

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=105,MOD=9999973;
int n,m,cur;
ll dp[2][MAXN][MAXN],res;

ll C(int a)
{return 1ll*a*(a-1)/2;}

int main()
{
    scanf("%d%d",&n,&m);
    
    dp[cur^1][0][0]=1;
    for(int i=1;i<=n;i++,cur^=1)
        for(int j=0;j<=m;j++) for(int k=0;j+k<=m;k++)
        {
            dp[cur][j][k]=dp[cur^1][j][k];
            if(k>=1) (dp[cur][j][k]+=dp[cur^1][j+1][k-1]*(j+1))%=MOD;
            if(j>=1) (dp[cur][j][k]+=dp[cur^1][j-1][k]*(m-j-k+1))%=MOD;
            if(j>=2) (dp[cur][j][k]+=dp[cur^1][j-2][k]*C(m-j-k+2))%=MOD;
            if(k>=2) (dp[cur][j][k]+=dp[cur^1][j+2][k-2]*C(j+2))%=MOD;
            if(k>=1) (dp[cur][j][k]+=dp[cur^1][j][k-1]*j*(m-j-k+1))%=MOD;
        }
    for(int i=0;i<=m;i++) for(int j=0;i+j<=m;j++)
        (res+=dp[cur^1][i][j])%=MOD;
    printf("%lld",res);
    return 0;
}

Reviews:

感觉现在想问题还是太定式了

更重要的是找到每道题的特点

对于总状态数较少的题目直接记录每种状态的个数$dp$即可,仅当状态数过多状压

猜你喜欢

转载自www.cnblogs.com/newera/p/9256810.html