牛客练习赛41B题-dp

题目链接:https://ac.nowcoder.com/acm/contest/373/B

Description

lililalala正在玩一种有N个回合的回合制RPG游戏,初始分数为0,第i个回合lililalala有如下两种选择。
A.将分数加上ai
B.将分数×-1
lililalala同样也很讨厌野兽数666,但是他很却喜欢数字-666。他想知道有多少种不同的方案使得N个回合后分数变为-666且在任何一个回合之后分数都不为666。如果两种方案有任何一个回合选择不同,就认为这两种方案是不同的。答案请对108+7取模。

Input
输入包含两行。
第一行一个整数 N(1≤N≤300)。
第二行N个整数a1a2a3…an(-666≤ a1a2a3…an≤666)

Output
输出一行一个整数–符合条件的不同方案数。

Sample Input
13
518 -643 -503 424 -76 -18 547 26 51 -647 -457 -5 329

Sample Output
2

思路
dp计数,因为有负数,且计算结果在300x(-666)到666x300之间,所以以200000为0。dp[i][j]=dp[i-1][j-a[i]]+dp[i-1][400000-j],这样会爆内存,所以要滚动数组,但不能一维,因为dp[j]又dp[j-a[i]]和dp[400000-j]得到,但是j-a[i]和400000-j在j的两侧,每次更新都会出错。所以要两个一维数组滚动。


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
35
36
37
38
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const long long mod = 1e8 + 7;
ll dp[2][400011];
ll a[400];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
dp[0][200000] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 400000; j++) {
if (j == 200666)
continue;
if (j >= a[i])dp[1][j] = (dp[0][j - a[i]] + dp[0][400000 - j])%mod;
else dp[1][j] = dp[0][400000 - j]%mod;

}
memcpy(dp[0], dp[1], sizeof(dp[0]));
memset(dp[1], 0, sizeof(dp[1]));
}
printf("%lld\n", dp[0][200000 - 666]);
//system("pause");

}

谢谢你请我吃糖果

你可能感兴趣的:(牛客练习赛41B题-dp)