Two Arrays CodeForces - 1288C

题面:https://vjudge.net/problem/CodeForces-1288C

这道题其实比较难想,据说题解一种方法是组合方法(然而我不会),我来总结总结dp的方法吧。

首先我们采用一个dp数组,dp[i][j][k]:在生成的a,b字符串中,第k个的数字分别是i,j,在满足这种情况下有多少种可能。

众所周知j一定要大于i,当k为1的时候满足j>i的情况下都只有一种可能(因为就一个数字)所以我们遍历的时候就要这样:

for(int i = 1; i <= n; i++)
		for(int j = i; j <= n; j++)
			dp[i][j][1] = 1;

接下来考虑递推关系式,我们知道dp[i][j][k]一定是从dp[x][y][k - 1]拓展出来的,我们不妨考虑考虑,当x <= i && y >= j时dp[x][y][k - 1]一定能拓展到dp[i][j][k],因为i代表a字符串第k位为i,按照题意i应该大于之前的所有,所以在k之前的x都要小于等于i,j也是一样的,但是要注意,j是递减的,所以在k之前的y都要大于等于j,并且小于题目限定的n。

我们就知道了,dp[i][j][k] = ∑(1,i)∑(j,n)dp[i][j][k - 1];

这个怎么算呢?

我们可以采用前缀和的方法处理,我们假设sum[i][j] = ∑(1,i)∑(j,n)dp[i][j][k - 1], 先计算对于每个i的所有j的和,然后再计算从1到i的和即可得到sum[i][j],而且,如果我们得到了每个i的所有j的和(复杂度O(n2)),再得到sum[i][j]就可以从sum[i - 1][j] + 第i行所有j之和得到。

我们就把sum用两次,第一次计算每行的j之和,易得代码:

for(int i = 1; i <= n; i++)
			for(int j = n; j >= i; j--)
				sum[i][j] = (sum[i][j + 1] + dp[i][j][k - 1]) % mod;

然后第二次计算从第1行到达第i行的和,按照上上段的方法:

for(int i = 1; i <= n; i++)
			for(int j = n; j >= i; j--)
				sum[i][j] = (sum[i][j] + sum[i - 1][j]) % mod;

注意,因为当j<i时毫无意义,所以直接不遍历这种情况。

最后得到的dp[i][j][k]对于每个i和j的和即为答案,我们可以用类似的方法解决。

注意点:每次采用sum时记得清零。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int mod = 1000000000 + 7;
int dp[1005][1005][15];
int sum[1005][1005];
int main()
{
	int n, m, ans = 0;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		for(int j = i; j <= n; j++)
			dp[i][j][1] = 1;
	for(int k = 2; k <= m; k++)
	{
		memset(sum, 0, sizeof(sum));//清零sum 
		for(int i = 1; i <= n; i++)
			for(int j = n; j >= i; j--)
				sum[i][j] = (sum[i][j + 1] + dp[i][j][k - 1]) % mod;//计算dp[i][j][k - 1]对于每个i的所有j之和 
		for(int i = 1; i <= n; i++)
			for(int j = n; j >= i; j--)//统计从1到i的每行和之和 
				sum[i][j] = (sum[i][j] + sum[i - 1][j]) % mod;
		for(int i = 1; i <= n; i++)
			for(int j = i; j <= n; j++)
				dp[i][j][k] = sum[i][j];
	}
	memset(sum, 0, sizeof(sum));
	for(int i = 1; i <= n; i++)
		for(int j = n; j >= i; j--)
			sum[i][j] = (sum[i][j + 1] + dp[i][j][m]) % mod;
	for(int i = 1; i <= n; i++)
		ans = (ans + sum[i][i]) % mod;
	printf("%d\n", ans);
	return 0;
}

  

posted @ 2020-05-21 15:37  funforever  阅读(137)  评论(0编辑  收藏  举报