【洛谷U142297】下棋

题目:

题目链接:https://www.luogu.com.cn/problem/U142297
\(n\) 个白色棋子,\(m\) 个黑色棋子,现在需要把他们排成一排,要求对于任意一段棋子,其中的白色棋子和黑色棋子的差不能超过 \(t\),求棋子排列方案数对 \(10^9+7\) 取模的结果。
\(n,m\leq 150,t\leq 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;
}
posted @ 2020-11-25 14:48  stoorz  阅读(347)  评论(0编辑  收藏  举报