666-RPG(计数dp入门)

链接: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;
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/88073036
666
RPG