2018 icpc徐州站网络赛 B BE, GE or NE dp

题目

题意:我和你玩游戏,刚开始有初始分数m,有n次操作,每次操作只能选a,b,c(为0不能选)三种之一,a不为0时,可以选择加a分,b不为0时,可以选择减b分,c不为0时,可以选择把当前分数变成相反数,我先选,你后选,一人一次来,我想让最后分数>=k,你想让最后分数<=l,n次操作结束后,分数大于等于 k 输出good,小于等于 l 输出bad,中间就输出nomal。

思路:由初始分数m计算出双方最优策略操作后最后的分数,太难,但是我们可以倒着想,在双方最优策略下,看看初始分数m可以由最后哪个分数得出来,这样就简单多了,设d[ i ][ j ]表示第 i 次操作时,当前分数为 j ,在双方最优策略后最后分数为d[ i ][ j ],可以知道,d[ n+1 ][ j ]肯定等于 j,那么怎么倒推求d[ i ][ j ]?当a,b,c都不为0时,如果 i 为奇数,代表我来选择,我肯定是想最后分数越来越高,那么d[ i ][ j ]=max(d[ i ][ j+a ],d[ i ][ j - b ],d[ i ][ -j ]),表示我有这三种选择,哪种选择最后的分越高,我就选哪个,i 为偶数,就取最小,由于数组下标不能为负数,以及这题上下届为-100到100,因此这题要把区间换成0到200,注意倒推的时候,加法别超过200,减法别小于0。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1005;
int a[maxn],b[maxn],c[maxn],d[maxn][205];
int main()
{
	int n,m,k,l,t;
	while(~scanf("%d%d%d%d",&n,&m,&k,&l))
	{
		k+=100,l+=100,m+=100;//-100到100的区间换成0到200 
		for(int i=1;i<=n;i++)
		scanf("%d%d%d",&a[i],&b[i],&c[i]);
		for(int i=0;i<=200;i++)d[n+1][i]=i;
		for(int i=n;i;i--)
		for(int j=0;j<=200;j++) 
		{
			int res1=0,res2=200;
			if(a[i])
			{
				t=min(200,j+a[i]);
				res1=max(res1,d[i+1][t]);
				res2=min(res2,d[i+1][t]);
			}
			if(b[i])
			{
				t=max(0,j-b[i]);
				res1=max(res1,d[i+1][t]);
				res2=min(res2,d[i+1][t]);
			}
			if(c[i])
			{
				t=200-j;
				res1=max(res1,d[i+1][t]);
				res2=min(res2,d[i+1][t]);
			}
			if(i&1) d[i][j]=res1;
			else d[i][j]=res2;
		}
		if(d[1][m]>=k)puts("Good Ending");
		else if(d[1][m]<=l)puts("Bad Ending");
		else puts("Normal Ending");
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值