【学习笔记】[ARC116F] Deque Game

这是一个组合博弈问题。

这是什么小丑题!!!只要大力分讨就行了,结果我却写了整整 2 h + 2h+ 2h+!!!

首先考虑 K = 1 K=1 K=1的经典模型。设序列长度为 N N N,记 p = n 2 p=\frac{n}{2} p=2n,给出下列结论(假设先手先取):

1.1 1.1 1.1 N N N为偶数,答案 max ⁡ ( a p , a p + 1 ) \max(a_{p},a_{p+1}) max(ap,ap+1)

1.2 1.2 1.2 N N N为奇数,答案 max ⁡ ( min ⁡ ( a p − 1 , a p ) , min ⁡ ( a p , a p + 1 ) ) \max(\min(a_{p-1},a_p),\min(a_p,a_{p+1})) max(min(ap1,ap),min(ap,ap+1))

后手先取的情况是对称的就不写了。

这肯定是可以通过 D P DP DP来严格证明的,但是也可以不严谨的感性理解一下:如果先手和后手都能保证取到一个相同的数 M M M,那么在双方都采取最优策略的情况下剩下的那个数就是 M M M

然后有一个结论:如果 N N N为奇数那么后手取比先手取更优。换句话说,如果一个序列为奇数那么谁也不会去动它,因为动它就说明自己先手取,这样就不优了。因此两个玩家都会选长度为偶数并且没有被操作过的序列进行操作,这样就会剩下若干个长度为奇数的序列,根据长度为偶数的序列的数目的奇偶性可以确定此时应该先手取还是后手取。直接模拟即可。

为什么这样是对的?假设对手把一个长度为偶数的序列取成了奇数,那么如果跟的话对手也会跟,这样相当于还是相当于先手在取一个长度为奇数的序列,这样的决策也是不优的。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)。需要排序,以及分类讨论。

#include<bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define db double using namespace std; int K,n; ll res; vector<int>nums[200005]; vector<int>values; int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>K; for(int i=1;i<=K;i++){ int len;cin>>len; for(int j=0;j<len;j++){ int x;cin>>x,nums[i].pb(x); } if(len==1){ res+=nums[i][0]; continue; } if(len%2==0){ n++; } } for(int i=1;i<=K;i++){ int len=nums[i].size(); if(len%2==0){ if(len==2){ int x=min(nums[i][0],nums[i][1]); int y=max(nums[i][0],nums[i][1]); assert(y>=x); res+=x,values.pb(y-x); } else if(n%2==0){ int x=nums[i][len/2-2],y=nums[i][len/2-1],z=nums[i][len/2],w=nums[i][len/2+1]; int val1=max(min(x,y),min(y,z)); int val2=max(min(y,z),min(z,w)); if(val1>val2)swap(val1,val2); res+=val1,values.pb(val2-val1); } else{ int x=nums[i][len/2-2],y=nums[i][len/2-1],z=nums[i][len/2],w=nums[i][len/2+1]; int val1=min(max(x,y),max(y,z)); int val2=min(max(y,z),max(z,w)); if(val1>val2)swap(val1,val2); res+=val1,values.pb(val2-val1); } } } sort(values.begin(),values.end()); reverse(values.begin(),values.end()); for(int i=0;i<values.size();i+=2){ res+=values[i]; } for(int i=1;i<=K;i++){ int len=nums[i].size(); if(len>1&&len%2==1){ int x=nums[i][len/2-1],y=nums[i][len/2],z=nums[i][len/2+1]; if(n%2==0){ res+=max(min(x,y),min(y,z)); } else{ res+=min(max(x,y),max(y,z)); } } } cout<<res; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529961.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示