• 【BZOJ2000】[HNOI2000]取石头游戏(贪心,博弈论)


    【BZOJ2000】[HNOI2000]取石头游戏(贪心,博弈论)

    题面

    BZOJ
    洛谷

    题解

    这题好神仙啊,窝不会QaQ。
    假装一下只有三个元素(a_{i-1},a_i,a_{i+1}),并且满足,(a_{i-1}le a_ige a_{i+1})那么肯定是(a_{i-1}+a_{i+1})(a_i)这样子分配的。那么两个人的差就是(a_{i-1}+a_{i+1}-a_i),那么我们把(i)和旁边两个元素直接合并就好了,反正只要知道了两个人的差和所有元素之和就能还原答案。
    不难发现这样子合并完之后序列要么单增要么单减。
    我们发现中间被分开的一段段是一个双端队列,可以从两端取。两侧被分割的部分是一个栈,只能一侧取。显然两侧的按照奇偶可以直接分配好谁去哪一侧。而剩下的部分因为单调,所以显然排序之后两个人一个个轮流取就好了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define MAX 1000100
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,l,r,fr,top;ll S[MAX],sum,ans;bool vis[MAX];
    bool check(int p){if(vis[p]||vis[p-1]||vis[p+1])return false;return S[p-1]<=S[p]&&S[p]>=S[p+1];}
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)
    	{
    		S[++top]=read();sum+=S[top];vis[top]=(S[top]==0);fr^=(bool)(S[top]);
    		while(top>=3&&check(top-1))S[top-2]=S[top-2]+S[top]-S[top-1],top-=2;
    	}
    	for(l=1;!vis[l]&&!vis[l+1]&&S[l]>=S[l+1];l+=2)ans+=(S[l]-S[l+1])*(fr?1:-1);
    	for(r=top;!vis[r]&&!vis[r-1]&&S[r]>=S[r-1];r-=2)ans+=(S[r]-S[r-1])*(fr?1:-1);
    	top=0;for(int i=l;i<=r;++i)if(!vis[i])S[++top]=S[i];sort(&S[1],&S[top+1]);
    	for(int i=top;i;--i)ans+=((top-i)&1)?-S[i]:S[i];
    	cout<<(sum+ans)/2<<' '<<(sum-ans)/2<<endl;
    	return 0;
    }
    
  • 相关阅读:
    csv导入数据到mongodb3.2
    [转]教你十分钟下载并破解IntelliJ IDEA(2017)
    Richard Stallman:让我们关注和尊敬自由软件教父
    约翰·卡马克和他的id Software
    fvwm:还是觉得你最好
    《程序员修炼之道》读书心得
    平铺式窗口管理器 Musca 初体验
    最小主义:我的Musca桌面环境
    Vim,Emacs排名不分先后
    在Emacs中画思维导图
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9852589.html
Copyright © 2020-2023  润新知