【带负数的dp+动态数组+剪枝】每次选择 *-1 或 +a[i] 问最后得到-666的方案数 牛客练习赛41 B.666RPG

牛客练习赛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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值