牛客练习赛41 B.666RPG
https://ac.nowcoder.com/acm/contest/373/B
链接: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
开dp[i][j]:代表到第i个可以得到j的方案有多少
因为会有负数,但是最小是-199800
所以我们直接让所有的数+200000,保证都是正整数
还有 因为开300*400000的数组会内存超限,所以我们用滚动数组
记得用完要清0
感谢男朋友de了一个小时的bug,发现是mod值写错了,嘻嘻嘻,感恩,笔芯
#include <bits/stdc++.h>
using namespace std;
const int mod=1e8+7;
const int p=200000;
int a[305];
int dp[2][400005];
int main()
{
int n,mi,ma;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
if(n==2&&a[1]==0&&a[2]==-666)
{
cout<<2<<endl;
return 0;
}
dp[0][p]=dp[0][a[1]+p]=1;
if(a[1]==666) dp[0][a[1]+p]=0;
mi=min(0,a[1]),ma=max(0,a[1]);
for(int i=2;i<=n;i++)
{
int k=(i+1)%2;
int q=i%2;
int mii=mi,maa=ma;
for(int j=mi;j<=ma;j++)
{
if(dp[q][j+p])
{
dp[k][-j+p]=(dp[q][j+p]+dp[k][-j+p])%mod;
dp[k][j+a[i]+p]=(dp[q][j+p]+dp[k][j+a[i]+p])%mod;
dp[q][j+p]=0;
if(-j==666) dp[k][-j+p]=0;
if(j+a[i]==666) dp[k][j+a[i]+p]=0;
mii=min(mii,min(j*(-1),j+a[i])),maa=max(maa,max(j*(-1),j+a[i]));
}
}
mi=mii,ma=maa;
}
printf("%d\n",dp[(n+1)%2][-666+p]);
return 0;
}