牛客练习赛41 B. 666RPG

  题目大意就是给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;
        }
    }
}
原文地址:https://www.cnblogs.com/eason9906/p/11754806.html