比赛时没做出来,表示被当时的198交9A给惊呆了。。。。。。
赛后才有了想法。
思路:Alice和Bob得金币总和为all,然后找到第一个前缀和大于all的数,这个位置是不可能到达的点。
eg:alice有10金币,bob有10金币,则all=20金币,共有5个商品5,6,7,8,9。这样的话第四个点8是不可能到达的,因为到那里需要26金币。
所以找到这个点之后我们要从他前面这个点开始往前递推,可以通过dp,dp[i]就表示到达i这个点时必胜需要多少个金币
还是这个样例eg:alice有10金币,bob有10金币,则all=20金币,共有5个商品5,6,7,8,9。
从第三个位置开始,显然dp[3]=7,因为只要能买得起这个商品,就是必胜,第四个点时无法到达的。
对于第二个位置,要获得必胜,有两种决策:
决策1:直接到达后继的必胜态。即dp[2]=6+dp[3]=13;
决策2:留给对手一个必败态,即对手下一次最多只能有(dp[3]-1)=6个金币,当前有all-5=15个金币,则dp[2]=15-6=9;
两者取较小值,即dp[2]=9;
对于第一个位置,同样的,有两种决策:
决策1:直接到达后继的必胜态。即dp[1]=5+dp[2]=14;
决策2:留给对手一个必败态,即对手下一次最多只能有(dp[2]-1)=8个金币,当前有all=20个金币,则dp[1]=20-8=12;
取较小值,dp[1]=12;得到了dp[1]后,只需要比较dp[1]和Alice的金币大小即可,alice的金币>=dp[1]时,alice必胜,否则必败。ect:这里10<dp[1],所以alice必败。
#include<stdio.h>
unsigned int all,sum[1111111],s[1111111],dp[1111111];
int main()
{
int i,n;
int x,y;
while(scanf("%d%d%d",&n,&x,&y)!=-1)
{
all=x+y;
int len=n,flag=0;
for(i=1;i<=n;i++)scanf("%u",&s[i]);
for(i=1;i<=n;i++)
{
sum[i]=sum[i-1]+s[i];
if(sum[i]>all){
len=i-1;
break;
}
}
dp[len]=s[len];
unsigned int tmp;
for(i=len-1;i>0;i--)
{
tmp=all-sum[i-1];
dp[i]=tmp-dp[i+1]+1;
tmp=dp[i+1]+s[i];
if(tmp<dp[i])dp[i]=tmp;
}
if(x>=dp[1])puts("ALICE");
else puts("BOB");
}
return 0;
}