HackerRank# Wet Shark and Two Subsequences

原题地址

对于给定的两个约束条件,可以通过联立方程组直接解出子序列A的和和子序列B的和,即sum(A) = (r + s) / 2,sum(B) = (r - s) / 2,假设|A|=|B|=n

所以问题变成了,在一个数组中求长度为n且子序列和为sum(A)或sum(B)有多少个。

假设count(n, s)表示长度为n且子序列和为s有多少个,则要求的是count(n, sum(A)) * count(n, sum(B)),其中1<=n<=m

或者通俗来说就是m个k-sum问题

求k-sum,如果用搜索的方法,时间复杂度是2^k,何况现在要求的是m个k-sum问题,即使排序+剪枝优化肯定也会超时(别问我是怎么知道的

所以只能选择动归,因为每次求k-sum的过程存在大量重复计算。

令f[i][j][k]表示从第i个元素开始,子序列长度为j,子序列和为k,这样的子序列有多少个

那么有地推公式:f[i][j][k] = f[i+1][j - 1][k - a[i]] + f[i + 1][j][k]

这个公式其实挺straightforward,跟背包问题是一样的。

由于sum(A)和sum(B)最大不过2000,所以k的范围是2000,另外i和j的范围分别是m的范围100,所以如果不做任何状态压缩,占用空间大概是2000*100*100*4*8约为640MB(用int存储),显然要爆。所以还必须状态压缩。

分析地推公式,明显压缩i那维,而且不难看出j和k必须从后向前推。还是跟背包问题一样。

代码:

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <vector>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cstring>
 7 using namespace std;
 8
 9 #define MAX_SIZE 128
10 #define MAX_SUM 2048
11 #define MOD 1000000007
12
13 long long a[MAX_SIZE];
14 int m, r, s;
15 long long f[MAX_SIZE][MAX_SUM];
16
17 int main() {
18     /* Enter your code here. Read input from STDIN. Print output to STDOUT */
19     int sa, sb;
20     long long res = 0;
21
22     cin >> m >> r >> s;
23     sa = (r + s) / 2;
24     sb = (r - s) / 2;
25     for (int i = 0; i < m; i++)
26         cin >> a[i];
27
28     memset(f, 0, sizeof(f));
29     f[0][0] = 1;
30     for (int i = m - 1; i >= 0; i--) {
31         for (int j = m; j >= 1; j--) {
32             for (int k = 2000; k >= 0; k--) {
33                 if (k >= a[i])
34                     f[j][k] = (f[j][k] + f[j - 1][k - a[i]]) % MOD;
35             }
36         }
37     }
38
39     for (int i = 1; i <= m; i++)
40         res = (res + (f[i][sa] * f[i][sb]) % MOD) % MOD;
41
42     cout << res << endl;
43     return 0;
44 }

第一次用的int,结果提交以后有些case是WA,考虑到DP问题基本上不会出现WA的情况,所以断定应该是数据溢出了,换成long long果然就没问题了。

时间: 2024-08-24 19:33:07

HackerRank# Wet Shark and Two Subsequences的相关文章

【CodeForces 621A】Wet Shark and Odd and Even

题 Today, Wet Shark is given n integers. Using any of these integers no more than once, Wet Shark wants to get maximum possible even (divisible by 2) sum. Please, calculate this value for Wet Shark. Note, that if Wet Shark uses no integers from the n 

【CodeForces 621C】Wet Shark and Flowers

题 There are n sharks who grow flowers for Wet Shark. They are all sitting around the table, such that sharks i andi + 1 are neighbours for all i from 1 to n - 1. Sharks n and 1 are neighbours too. Each shark will grow some number of flowers si. For i

矩阵乘法&amp;&amp;dp加速矩阵的思路(E. Wet Shark and Blocks)

There are b blocks of digits. Each one consisting of the same n digits, which are given to you in the input. Wet Shark must choose exactly one digit from each block and concatenate all of those digits together to form one large integer. For example,

Wet Shark and Bishops(思维)

Today, Wet Shark is given n bishops on a 1000 by 1000 grid. Both rows and columns of the grid are numbered from 1 to 1000. Rows are numbered from top to bottom, while columns are numbered from left to right. Wet Shark thinks that two bishops attack e

CodeForces 621A Wet Shark and Odd and Even

水题 #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<vector> #include<algorithm> using namespace std; int n; long long a[100000+10]; int main() { scanf("%d",&n); for(int i=0;i<

CodeForces 621C Wet Shark and Flowers

方法可以转化一下,先计算每一个鲨鱼在自己范围内的数能被所给素数整除的个数有几个,从而得到能被整除的概率,设为f1,不能被整除的概率设为f2. 然后计算每相邻两只鲨鱼能获得钱的期望概率,f=w[id1].f1*w[id2].f2+w[id1].f2*w[id2].f1+w[id1].f1*w[id2].f1; f*2000就是这两只鲨鱼能获得的期望金钱,然后枚举一下所有相邻的鲨鱼,累加即可. #include<cstdio> #include<cstring> #include<

CodeForces 621B Wet Shark and Bishops

记录一下每个对角线上有几个,然后就可以算了 #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<vector> #include<algorithm> using namespace std; const int maxn=2000+10; int n; long long w1[maxn]; long long w2[maxn]; l

【CodeForces 621B】Wet Shark and Bishops

题 题意 1000*1000的格子里,给你n≤200 000个点的坐标,求有多少对在一个对角线上. 分析 如果求每个点有几个共对角线的点,会超时. 考虑到对角线总共就主对角线1999条+副对角线1999条,我们可以求每个对角线有几对点. 同一条主对角线上的元素有a[i]个,就有C(a[i],2)对点: 同一条副对角线上的元素有b[i]个,就有C(b[i],2)对点. 读入x和y后, x+y相同的就在同一副对角线,x+y范围是(2,2000), x-y相同的就是同一主对角线,x-y范围是(-999

Codeforces Round #341 Div.2 C. Wet Shark and Flowers

题意: 不概括了..太长了.. 额第一次做这种问题 算是概率dp吗? 保存前缀项中第一个和最后一个的概率 然后每添加新的一项 就解除前缀和第一项和最后一项的关系 并添加新的一项和保存的两项的关系 这里关系指的是两者相邻会产生的额外收入(其中一个满足条件就能得到 因此公式是 2000 * (rate[a] * rate[b] + rate[a] * ( 1 - rate[b]) + rate[b] * (1 - rate[a])) 至于一开始为什么老是调不过去呢..我发现添加第三项的时候前两项是不