链接:https://ac.nowcoder.com/acm/contest/373/B
来源:牛客网
lililalala正在玩一种有 N N个回合的回合制RPG游戏,初始分数为0,第 i i个回合lililalala有如下两种选择。
A.将分数加上 ai ai
B.将分数 ×-1 ×-1
lililalala同样也很讨厌野兽数 666 666,但是他很却喜欢数字 -666 -666。他想知道有多少种不同的方案使得 N N个回合后分数变为 -666 -666且在任何一个回合之后分数都不为 666 666。
如果两种方案有任何一个回合选择不同,就认为这两种方案是不同的。
答案请对 108+7 108+7取模。
输入描述:
输入包含两行。
第一行一个整数 N(1≤N≤300) N(1≤N≤300)。
第二行 N N个整数 a1a2a3...an(-666≤ a1a2a3...an≤666) a1a2a3...an(-666≤ a1a2a3...an≤666)。
输出描述:
输出一行一个整数--符合条件的不同方案数。
示例1
输入
3 -333 -333 -333
输出
1
说明
仅一种符合条件的方案
第一回合选择将分数 ×−1 ×−1。分数为 0 0
第二回合选择将分数加上 -333 -333。分数为 -333 -333
第三回合选择将分数加上 -333 -333。分数为 -666 -666
示例2
输入
3 333 333 333
输出
0
示例3
输入
13 518 -643 -503 424 -76 -18 547 26 51 -647 -457 -5 329
输出
2
透过这道题让我学会了如何处理小于零做数组下标的情况。这题和上次训练赛的A题是一致的,都是计数dp,将数作为数组下标当成状态。
如何处理小于零呢?
统统加上一个非常大的数N,N就是代表0.N-666就是-666,N+666就是状态666,然后DP一下就可以了。稍微滚动数组优化一下节约空间。如何从6变成-6?也就是N+6->N-6;直接2*N-(N+6)=N-6;是不是感觉很妙。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=300*666;
const int maxn=300*2*666+10,mod=1e8+7;
int a[305],cur,n;
ll dp[2][maxn],ans;
int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
dp[0][N]=1;
for(int i=1;i<=n;i++)
{
cur=1-cur;
for(int j=0;j<maxn;j++) dp[cur][j]=0;
for(int j=0;j<maxn;j++)
{
if(dp[!cur][j])
{
dp[cur][j+a[i]]=(dp[cur][j+a[i]]+dp[!cur][j])%mod;
dp[cur][2*N-j]=(dp[cur][2*N-j]+dp[!cur][j])%mod;
}
}
dp[cur][N+666]=0;
if(i==n) ans=(ans+dp[cur][N-666]);
}
cout<<ans<<endl;
}