题目大意:给定对方的出牌序列以及你的手牌,双方手牌一共是一个1到2n的全排列,一开始是点大胜出,你可以在任意时刻改一次规则变成点小胜出,求最多能赢多少次
用贪心的思想,肯定一开始尽量用点大的,改规则之后用点小的,每次用卡的时候都用那个恰好能赢的卡是最优的,如果没有就用最小的,然后枚举一下改规则的时间,这样可以O(N^2)算出答案
我们考虑先不枚举改规则的中间点,用F[i]表示前i个回合不改规则最多能赢多少个,这个可以直接扫一遍得出答案,在设G[i]为从i开始改规则后面(包括i)能赢多少个,这个同样扫一遍就能知道答案,那么最终答案就是最大的F[i]+G[i+1]
为什么呢?首先F和G分别都是在没有手牌限制的情况下求出的答案,所以F+G一定不会比答案更差
其次,F和G方案中可能会有重复的手牌,但是可以经过调整变成不重复的手牌且不让答案变得更差(因为前面点大获胜,后面点小获胜),所以F+G一定不会比答案更优
所以F+G的最大值就是答案
(我写的是线段树,但是实际上用set就可以过....)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100010
using namespace std;
int zyh[N],sxh[N],a[N];
int mi[N<<2],l[N<<2],r[N<<2],t[N<<2],b[N];
void pup(int x)
{
mi[x]=min(mi[x<<1],mi[x<<1|1]);
}
void pud(int x)
{
if(!t[x]) return;
int i;
for(i=0;i<2;i++)
{
mi[x<<1|i]+=t[x];
t[x<<1|i]+=t[x];
}
t[x]=0;
}
void build(int now,int ll,int rr)
{
l[now]=ll;r[now]=rr;
if(ll==rr)
{
mi[now]=b[ll];
return;
}
int mid=(ll+rr)>>1;
build(now<<1,ll,mid);
build(now<<1|1,mid+1,rr);
pup(now);
}
int checkmi(int now,int ll,int rr)
{
if(l[now]==ll&&r[now]==rr) return mi[now];
pud(now);
int mid=(l[now]+r[now])>>1;
if(rr<=mid) return checkmi(now<<1,ll,rr);
else if(ll>mid) return checkmi(now<<1|1,ll,rr);
else return min(checkmi(now<<1,ll,mid),checkmi(now<<1|1,mid+1,rr));
}
void change(int now,int ll,int rr,int v)
{
if(l[now]==ll&&r[now]==rr)
{
t[now]+=v;
mi[now]+=v;
return;
}
pud(now);
int mid=(l[now]+r[now])>>1;
if(rr<=mid) change(now<<1,ll,rr,v);
else if(ll>mid) change(now<<1|1,ll,rr,v);
else
{
change(now<<1,ll,mid,v);
change(now<<1|1,mid+1,rr,v);
}
pup(now);
}
int ff[N],gg[N];
int main()
{
int n;
scanf("%d",&n);
int i,j,x,y;
for(i=1;i<=n;i++)
{
scanf("%d",&zyh[i]);
a[i]=zyh[i];
}
sort(zyh+1,zyh+n+1);
int now=1,cn=0;
for(i=1;i<=2*n;i++)
{
if(zyh[now]==i) now++;
else
{
cn++;
sxh[cn]=i;
}
}
now=1;
b[0]=0;
for(i=1;i<=n;i++)
{
b[i]=b[i-1]-1;
while(zyh[now]<sxh[i]&&now<=n) now++,b[i]++;
}
build(1,1,n);
int L,R,mid;
for(i=n;i>=1;i--)
{
ff[n-i]=n+checkmi(1,n-i+1,n);
L=n-i+1;R=n;
if(a[i]<sxh[n])
{
while(L<R)
{
mid=(L+R)>>1;
if(sxh[mid]<a[i]) L=mid+1;
else R=mid;
}
change(1,L,n,-1);
}
}
memset(t,0,sizeof(t));
for(i=1;i<=n;i++)
{
a[i]=2*n+1-a[i];
zyh[i]=2*n+1-zyh[i];
sxh[i]=2*n+1-sxh[i];
}
for(i=1;i<=n/2;i++)
{
swap(zyh[i],zyh[n+1-i]);
swap(a[i],a[n-i+1]);
swap(sxh[i],sxh[n+1-i]);
}
now=1;
for(i=1;i<=n;i++)
{
b[i]=b[i-1]-1;
while(zyh[now]<sxh[i]&&now<=n) now++,b[i]++;
}
build(1,1,n);
for(i=n;i>=1;i--)
{
gg[i]=n+checkmi(1,n-i+1,n);
L=n-i+1;R=n;
if(a[i]<sxh[n])
{
while(L<R)
{
mid=(L+R)>>1;
if(sxh[mid]<a[i]) L=mid+1;
else R=mid;
}
change(1,L,n,-1);
}
}
int ans=0;
for(i=0;i<=n;i++)
ans=max(ans,ff[i]+gg[i]);
printf("%d",ans);
}