2019牛客多校第一场E ABBA 贪心 + DP

题意:问有多少个有(n + m)个A和(n + m)个B的字符串可以凑出n个AB和m个BA。

思路:首先贪心的发现,如果从前往后扫,遇到了一个A,优先把它看成AB的A,B同理。这个贪心策略用邻项交换很好证明。之后,我们设dp[i][j]为填了i个A和j个B的字符串不违法的方案数。什么叫不违法呢?有一些方案是一定不可以凑出n个AB和m个BA的,比如如果i - n > j了就不行:现在已经有i个A,其中有n个A用来充当AB的A,那么剩下的A只能去充当BA的A,但是假如现在你的B的个数j小于的BA的A的个数,那么你后面有多少个B都于事无补了,一定会少一个BA。所以状态必须满足两个不等式:i - n <= j, j - m <= i。只要满足这两个条件,状态直接转移就可以了。

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 2010;
const LL mod = 1e9 + 7;
LL dp[maxn][maxn];
int n, m, x, y;
bool valid(int A, int B) {
	return (B >= A - n) && (A >= B - m);
}
void solve() {
	for (int i = 0; i <= n + m; i++) {
		for (int j = 0; j <= n + m; j++) {
			dp[i][j] = 0;
			if(i == 0 && j == 0) dp[i][j] = 1;
			if(!valid(i, j)) continue;
			if(j) dp[i][j] += dp[i][j - 1];
			if(i) dp[i][j] += dp[i - 1][j];
			dp[i][j] %= mod;
		}
	}
	printf("%lld\n", dp[n + m][n + m]);
}
int main() {
	while(~scanf("%d%d", &n, &m)) {
		solve();
	}
}

  

猜你喜欢

转载自www.cnblogs.com/pkgunboat/p/11212372.html