其他分享
首页 > 其他分享> > jzoj4684. 【GDOI2017模拟8.11】卡牌游戏

jzoj4684. 【GDOI2017模拟8.11】卡牌游戏

作者:互联网

原来想这道题时田忌赛马问题。。。从贪心想。。。一直没想出来。。。naive

事实上,这道题其实就是田忌赛马问题,但是有添加操作,所以单纯排序不行了

注意到d同学的贪心策略也可以表示为如下:(默认规则为牌大的赢)

1.将d同学的牌从小到大排序

2.从小到大枚举d同学的每一张牌,对于现在这张牌,找到p同学手上第一个比它小的牌,删去这张牌(没有就不删)

另一种规则类似

我们显然不可以暴力维护,考虑权值线段树

每次只添加一张牌,相当于单点修改,每次添加的牌直接加到其权值上

对每个节点记l1表示d同学还有几张牌,r1表示p同学有几张牌,c1表示答案个数

将树上每个节点右儿子的l1用于消去左儿子的r1,然后上传到该节点

这样为什么是正确的呢?因为这样子可以让d的牌首先和区间较小但是对应值大的p的牌匹配,再让未匹配好的d的牌和祖先的左儿子的区间更大而对应值小的p的牌匹配(有点绕,菜鸡博主语文太差,请理解)

只要访问根节点即可完成查询

最后对n+1种规则改变情况取最大值就好了

代码:

#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,a[N],b[N],v[N],f[N],g[N],l1[N*10],r1[N*10],c1[N*10],l2[N*10],r2[N*10],c2[N*10],ans;
void i1(int o,int l,int r,int x,int t){
    if(l==r){
        if(!t)l1[o]++;
        else r1[o]++;
        return;
    }
    int md=(l+r)/2;
    if(x<=md)i1(o*2,l,md,x,t);
    else i1(o*2+1,md+1,r,x,t);
    c1[o]=r1[o]=l1[o]=0;
    if(l1[o*2+1]>=r1[o*2]){
        c1[o]+=r1[o*2];
        l1[o]+=l1[o*2+1]-r1[o*2];
    }
    else{
        c1[o]+=l1[o*2+1];
        r1[o]+=r1[o*2]-l1[o*2+1];
    }
    r1[o]+=r1[o*2+1];
    l1[o]+=l1[o*2];
    c1[o]+=c1[o*2]+c1[o*2+1];
}
void i2(int o,int l,int r,int x,int t){
    if(l==r){
        if(!t)l2[o]++;
        else r2[o]++;
        return;
    }
    int md=(l+r)/2;
    if(x<=md)i2(o*2,l,md,x,t);
    else i2(o*2+1,md+1,r,x,t);
    c2[o]=l2[o]=r2[o]=0;
    if(l2[o*2]>=r2[o*2+1]){
        c2[o]+=r2[o*2+1];
        l2[o]+=l2[o*2]-r2[o*2+1];
    }
    else{
        c2[o]+=l2[o*2];
        r2[o]+=r2[o*2+1]-l2[o*2];
    }
    r2[o]+=r2[o*2];
    l2[o]+=l2[o*2+1];
    c2[o]+=c2[o*2]+c2[o*2+1];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        v[a[i]]=1;
    }
    int ct=0;
    for(int i=1;i<=2*n;i++)
        if(!v[i])b[++ct]=i;
    reverse(b+1,b+n+1);
    for(int i=1;i<=n;i++){
        i1(1,1,n*2,a[i],1);
        i1(1,1,n*2,b[i],0);
        f[i]=c1[1];
    }
    ans=max(ans,f[n]);
    for(int i=n;i;i--){
        i2(1,1,n*2,a[i],1);
        i2(1,1,n*2,b[i],0);
        ans=max(ans,c2[1]+f[i-1]);
    }
    printf("%d",ans);
}

 

标签:r1,r2,int,jzoj4684,卡牌,l2,l1,c1,GDOI2017
来源: https://www.cnblogs.com/rilisoft/p/11106583.html