【洛谷U142297】下棋

题目:

题目链接: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;
}
原文地址:https://www.cnblogs.com/stoorz/p/14036071.html