Description
有 (n) 个白色棋子,(m) 个黑色棋子,现在需要把他们排成一排,要求对于任意一段棋子,其中的白色棋子和黑色棋子的差不能超过 (k)。
(nleq 150,kleq 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