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的情况下都只有一种可能(因为就一个数字)所以我们遍历的时候就要这样:
1 2 3 | 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之和,易得代码:
1 2 3 | 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行的和,按照上上段的方法:
1 2 3 | 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代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #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; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步