题目:
题目链接:https://www.luogu.com.cn/problem/U142297
有 (n) 个白色棋子,(m) 个黑色棋子,现在需要把他们排成一排,要求对于任意一段棋子,其中的白色棋子和黑色棋子的差不能超过 (t),求棋子排列方案数对 (10^9+7) 取模的结果。
(n,mleq 150,tleq 20)。
思路
假设我们目前取了 (i) 个黑棋和 (j) 个白棋,在上一次取棋之前都是满足白色棋子和黑色棋子的差不超过 (k),那么如何判断此时黑白棋子的差是否超过 (k)?
我们可以分成黑减白以及白减黑两种方法计算,以黑减白为例,我们知道此时 (i-j) 的值,我们需要知道前面是否存在某一个时刻黑白棋子分别有 (i',j') 个,且满足 ((i-i')-(j-j')>k)。
显然上式等价于 ((i-j)+(j'-i')>k),所以我们只需要知道之前白棋减黑棋的最大值即可判断。
所以设 (f[i][j][k][l]) 表示取了 (i) 个黑棋,(j) 个白棋,之前黑减白最大值为 (k),白减黑最大值为 (l) 的方案数。
转移就分下一个棋子取黑棋还是白棋即可。以拿黑棋来说,有
[f[i+1][j][max(k,i+1-j)][l]gets f[i][j][k][l]
]
时空复杂度均为 (O(nmt^2))。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=160,M=25,MOD=1e9+7;
int n,m,t,ans,f[N][N][M][M];
int main()
{
scanf("%d%d%d",&n,&m,&t);
f[0][0][0][0]=1;
for (int i=0;i<=n;i++)
for (int j=0;j<=m;j++)
for (int k=0;k<=t;k++)
for (int l=0;l<=t;l++)
{
if (i-j+l>t || j-i+k>t) f[i][j][k][l]=0;
if (i+1-j+l<=t && i<n)
f[i+1][j][max(i+1-j,k)][l]=(f[i+1][j][max(i+1-j,k)][l]+f[i][j][k][l])%MOD;
if (j+1-i-k<=t && j<m)
f[i][j+1][k][max(j+1-i,l)]=(f[i][j+1][k][max(j+1-i,l)]+f[i][j][k][l])%MOD;
}
for (int i=0;i<=t;i++)
for (int j=0;j<=t;j++)
ans=(ans+f[n][m][i][j])%MOD;
printf("%d",ans);
return 0;
}