[机房测试] 下棋

Description

\(n\) 个白色棋子,\(m\) 个黑色棋子,现在需要把他们排成一排,要求对于任意一段棋子,其中的白色棋子和黑色棋子的差不能超过 \(k\)

\(n\leq 150,k\leq 20\)

Solution

考虑增量构造,假设前 \(i-1\) 个棋子全满足限制,再增加一个棋子还需要满足什么条件?只需要保证新出来的 \(i\) 个区间中差值最大的也小于等于 \(K\),所以只需要记录后缀差值的最大值即可转移。记 \(dp_{i,j,k,l}\) 表示用了 \(i\) 个白子 \(j\) 个黑子,白减黑的最大值为 \(k\),黑减白的最大值为 \(l\) 的方案数。转移比较显然。复杂度 \(O(n^2k^2)\)

#include<stdio.h>

const int N=153;
const int M=21;
const int Mod=1e9+7;

int n,m,K;
int dp[N][N][M][M];

inline void add(int &x,int y){x+=y; if(x>=Mod) x-=Mod;}
inline int max(int x,int y){return x>y? x:y;}
inline int min(int x,int y){return x<y? x:y;}

int main(){
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    dp[0][0][0][0]=1;
    for(int i=0;i<=n;i++)
    for(int j=0;j<=m;j++)
    for(int l=0,rgl=min(K,i);l<=rgl;l++)
    for(int r=0,rgr=min(K,j);r<=rgr;r++){
        if(i!=n&&l!=K) add(dp[i+1][j][l+1][max(0,r-1)],dp[i][j][l][r]);
        if(j!=m&&r!=K) add(dp[i][j+1][max(0,l-1)][r+1],dp[i][j][l][r]);
    }
    int ans=0;
    for(int l=0,rgl=min(K,n);l<=rgl;l++)
        for(int r=0,rgr=min(K,m);r<=rgr;r++) add(ans,dp[n][m][l][r]);
    printf("%d",ans);
}

// 150 150 19
posted @ 2021-11-02 20:46  Kreap  阅读(95)  评论(0编辑  收藏  举报