题解:P13093 [FJCPC 2025] 卡牌游戏
性质挖掘 + 前缀和 + 贪心 + STL set + STL 二分查找
首先要能手玩样例发现出一个性质:对于区间
由于考虑区间长度为奇数时等价于修改一个区间
在知道了上面那个性质之后,就可以考虑枚举长度为偶数的区间
偶数下标元素之和同理,但其实可以直接通过
但上面这个枚举
对于前面当操作
定义
根据贪心的考虑,要让最坏情况下得到的数字之和最大,即考虑让当前操作
那么显然两者尽可能接近,即考虑让
即让
那么可以考虑每次枚举右端点
具体地说:记
细节一:用 STL set 维护
细节二:由于
细节三:在 STL set 上查找
代码如下:
#define rep(x,y,z) for(int x=y;x<=z;x++)
typedef long long LL;
const int N=2e5+5;
int n;
int a[N];
LL diff[N];
void solve(){
cin>>n;
rep(i,1,n*2) cin>>a[i];
LL sum=0;
LL odd_sum=0,even_sum=0;
rep(i,1,n*2){
sum+=a[i];
if(i&1) odd_sum+=a[i];
else even_sum+=a[i];
diff[i]=odd_sum-even_sum;
}
set<LL> se[2];
LL ans=0;
rep(r,0,n*2){
if(r){
LL val=sum/2+diff[r]-odd_sum;
auto it=se[r&1].lower_bound(val);
if(it!=se[r&1].end()){
LL res_odd=*it-diff[r]+odd_sum;
ans=max(ans,min(res_odd,sum-res_odd));
}
if(it!=se[r&1].begin()){
it--;
if(it!=se[r&1].end()){
LL res_odd=*it-diff[r]+odd_sum;
ans=max(ans,min(res_odd,sum-res_odd));
}
}
}
se[r&1].insert(diff[r]);
}
cout<<ans;
}