BZOJ上的Source是骗子QAQ这题根本不是SG函数QAQ
Description
A 公司正在举办一个智力双人游戏比赛—-取石子游戏,游戏的获胜者将会获得 A 公司提
供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛。
与经典的取石子游戏相比,A公司举办的这次比赛的取石子游戏规则复杂了很多:
总共有N堆石子依次排成一行,第i堆石子有 ai个石子。
开始若干堆石子已被 A公司故意拿走。
然后两个玩家轮流来取石子,每次每个玩家可以取走一堆中的所有石子,但有一个限
制条件:一个玩家若要取走一堆石子,则与这堆石子相邻的某堆石子已被取走(之前被
某个玩家取走或开始被A公司故意拿走)。注意:第 1堆石子只与第 2堆石子相邻,第
N堆石子只与第N-1堆石子相邻,其余的第 i堆石子与第i-1堆和第 i+1 堆石子相邻。
所有石子都被取走时,游戏结束。谁最后取得的总石子数最多,谁就获得了这场游戏
的胜利。
作为这次比赛的参赛者之一,绝顶聪明的你,想知道对于任何一场比赛,如果先手者和后
手者都使用最优的策略,最后先手者和后手者分别能够取得的总石子数分别是多少。
Input
第一行是一个正整数N,表示有多少堆石子。输入
文件第二行是用空格隔开的N个非负整数a1, a2, …, aN,其中ai表示第i堆石子有多少个石子,
ai = 0表示第i堆石子开始被A公司故意拿走。输入的数据保证0≤ai≤100,000,000,并且至少有
一个i使得ai = 0。30%的数据满足2≤N≤100,100%的数据满足2≤N≤1,000,000。
Output
仅包含一行,为两个整数,分别表示都使用最优策略时,最后先手者
和后手者各自能够取得的总石子数,并且两个整数间用一个空格隔开。
Sample Input
8
1 2 0 3 7 4 0 9
Sample Output
17 9
样例解释:两个玩家都使用最优策略时取走石子的顺序依次为9, 2, 1, 4, 7, 3,因此先手
者取得9 + 1 + 7 = 17个石子,后手者取得2 + 4 + 3 = 9个石子。
HINT
Source
Sg
再次重复:这题根本不是SG函数!!!QAQ
其实这题是个贪心.
可以发现对每个连续的石子区间,决策与奇偶相关的.(奇数位的和及偶数位的和)
当石子序列出现了如 ai−1<ai>ai+1 的形式,显然我们可以把这部分石头合并一下变成 ai−1+ai+1−ai ,因为我们可以发现两个人的最优决策就是分别取 ai−1+ai+1 和 ai .这个看起来挺对的嗯>_<.
我们可以感受一下之后就可以贪心了>_<(什么鬼!)
好吧其实是这样的:我们可以发现整个数列被我们化成了两人取数之差的形式.最后把差值记录一下,再用初始数列每项的和计算一下就能得到答案.
需要注意:过程中尽量开LongLong因为好像有不少地方会爆int?
以及合并之后别忘了删除掉多余的元素!
#include
#include
#include
#include
#include
#define MAXN 1000100
#define LL long long
using namespace std;
LL a[MAXN],s[MAXN];
int prev[MAXN],next[MAXN];
LL n,num;
int b[MAXN];
int head,tail,top;
LL sum,delta;
inline void in(LL &x)
{
char ch=getchar();x=0;
while (!(ch>='0'&&ch<='9')) ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
inline void del(int x)
{
b[x]=1;
prev[next[x]]=prev[x];
next[prev[x]]=next[x];
}
inline bool comp(LL a,LL b)
{
return a>b;
}
int main()
{
in(n);
for (int i=1;i<=n;i++)
{
in(a[i]);b[i]=!a[i];sum+=a[i];
next[i]=i+1;prev[i]=i-1;num+=!b[i];
}
next[0]=1;prev[n+1]=n;head=1;tail=n;
bool flag=1;
while (flag&&head0;
if (!b[head]&&!b[next[head]]&&a[head]>=a[next[head]])
{
delta+=(num&1)?a[head]-a[next[head]]:a[next[head]]-a[head];
int tmp=next[next[head]];
del(next[head]);del(head);head=tmp;flag=1;
}
if (!b[tail]&&!b[prev[tail]]&&a[tail]>=a[prev[tail]])
{
delta+=(num&1)?a[tail]-a[prev[tail]]:a[prev[tail]]-a[tail];
int tmp=prev[prev[tail]];
del(prev[tail]);del(tail);tail=tmp;flag=1;
}
for (int i=head;i<=tail;i++)
if (!b[i]&&prev[i]>0&&next[i]<=n&&!b[prev[i]]&&!b[next[i]]&&a[i]>=a[prev[i]]&&a[i]>=a[next[i]])
{
flag=1;a[i]=a[prev[i]]+a[next[i]]-a[i];
if (prev[i]==head) head=i;
if (next[i]==tail) tail=i;
del(prev[i]);del(next[i]);
}
}
for (int i=1;i<=n;i++)
if (!b[i]) s[++top]=a[i];
sort(s+1,s+top+1,comp);
for (int i=1;i<=top;i++) delta+=(i&1)?s[i]:-s[i];
cout<<(sum+delta)/2<<' '<<(sum-delta)/2<