题目大意就是给n个数,然后有n个回合,在第i个回合操作有2种,一种是对当前数*-1,第二种是对当前数+ai,问你n回合后数变成-666的操作方案数是多少?另外数的初始值是0,还有在一个合法的方案里,不能有某个回合结束后数变成了666
这题用的是计数dp,定义dp[i][j]表示第i个回合结束之后,数变成j的方案个数。初始化是dp[0][0]=1,其余为0。状态转移的话是dp[i][-j]+=dp[i-1][j],dp[i][j+a[i]]+=dp[i-1][j],然后跳过666的转移。然后因为数的变化范围是-666*300到666*300当时数组的下标是不能为负数的,所以在这里做了个映射,把-666*300到666*300这个区间映射到-666*300+700*300到666*300+700*300这个区间了,相当于第i个回合结束后数为j的方案数为dp[i][j+700*300],开二维爆内存了,然后就滚掉一维。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define tmp 210000
const ll mod=1e8+7;
ll dp[2][420000];
int a[305];
int main()
{
int n,pos=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&(a[i]));
dp[0][0+tmp]=1LL;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=(420000-1);j++) dp[(pos+1)%2][j]=0LL;
for(int j=-199800;j<=199800;j++)
if(dp[pos][j+tmp])
{
if(j+a[i]!=666)
dp[(pos+1)%2][j+a[i]+tmp]=(dp[(pos+1)%2][j+a[i]+tmp]+dp[pos][j+tmp])%mod;
if((-1*j)!=666)
dp[(pos+1)%2][-1*j+tmp]=(dp[(pos+1)%2][-1*j+tmp]+dp[pos][j+tmp])%mod;
}
pos=(pos+1)%2;
if(i==n)
{
cout<<dp[pos][-666+tmp]<<endl;
return 0;
}
}
}