题目链接: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<iostream> #include<cstdio> #include<vector> #include<cstring> #include<string> #include<algorithm> #include<set> #include<cstdlib> #include<map> #include<queue> #include<cmath> 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]);
}
|