码迷,mamicode.com
首页 > 其他好文 > 详细

AGC 036E ABC String

时间:2019-08-25 15:59:24      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:cpp   bit   证明   set   ret   void   get   i++   一个   

相邻的相等串直接当成一个串。

不妨设\(A\le B,A\le C\)

考虑\(A\)选哪些已经确定的时候,如何调整\(B\)\(C\)

把不用的\(A\)提出去之后再合并一下形成串\(T\)。不难发现\(A\le B, A\le C\)仍然成立。

  1. \(B=C\)的情况

我们直接删除连续的\(BC\)串即可。

容易证明一定能够做到。

  1. \(B\ne C\)的情况,不妨设\(B<C\)

现在有\(A+1?\)个子串。定义\(\text{unit string}?\)为长度为\(1?\)并且左右都会\(>1?\)的子串。设\(x,y?\)分别为包含\(B?\)的串数量和\(C?\)\(\text{unit string}?\)数量。

如果\(x<y\)\(B\)\(C\)的个数不可能相等。因为其他位置上\(B-C\)的数量最大是\(1?\)

如果\(x\ge y\),那么是一定可以只删除\(C\)就直接做到\(B= C\)的。

\(b_1,b_2,c_1,c_2\)分别表示\(B/C\text{的string/unit string}\)个数。

现在相当于要求\(b_2\le c_1\)并且\(c_2\le b_1?\)

首先两个条件只会不满足一个。

  1. 删掉一个\(A\),四个值最多\(-1\)
  2. 如果删掉的\(A\)左边是一个\(b_2\)类型的串,\(b_2\)\(-1\)\(c_1\)不会变。那直接依次删掉即可。根据\((1)\),这样显然达到最优秀了

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 4e6+5;
int s[N],n;char tmple[N];
int cnt[3];
int p[3]={0,1,2};
 
inline void _swap(int x,int y){
    swap(p[x],p[y]);
    for(int i=1;i<=n;i++){
        if(s[i]==x)s[i]=y;
        else if(s[i]==y)s[i]=x;
    }
}
 
int b1,b2,c1,c2;
vector<int> pc2;bool ban[N];
 
void get(int l,int r){
    if(l>r)return ;
    int cntt[3]={0,0,0};
    for(int i=l;i<=r;i++){
        cntt[s[i]]++;
    }
    if(cntt[2]==0||cntt[1]==0){
        if(cntt[2]&&l>1&&r<n)c2++,pc2.push_back(l-1);
        if(cntt[1]&&l>1&&r<n)b2++;
    }
    if(cntt[2])c1++;
    if(cntt[1])b1++;
}
 
void Sol(int l,int r){
    if(l>r)return ;
    if(l==r){
        if(l==1||l==n){
            if(s[l]==2&&cnt[2]>cnt[1])cnt[2]--,ban[l]=1;
        }
    }
    if(l==r)return ;
    if(s[l]==2&&cnt[2]>cnt[1])cnt[2]--,ban[l]=1;
    if(s[r]==2&&cnt[2]>cnt[1])cnt[2]--,ban[r]=1;
}
 
int now,tar;
void Sol2(int l,int r){
    if(l>r)return ;
    while(l<r&&now>tar){
        if(l+1>=r && l!=1 && r!=n)break;
        now--;ban[l]=ban[l+1]=1;l+=2;
    }
}
 
int main()
{
    scanf("%s",tmple+1);int lll=strlen(tmple+1);
    for(int i=1;i<=lll;i++)if(i==1||tmple[i]!=tmple[i-1])s[++n]=tmple[i]-'A';
    for(int i=1;i<=n;i++)cnt[s[i]]++;
    for(int i=0;i<3;i++)for(int j=i+1;j<3;j++)if(i!=j){
        if(cnt[i]>cnt[j]){
            _swap(i,j);
            swap(cnt[i],cnt[j]);
        }
    }
    int lst=0;
    for(int i=1;i<=n;i++)
        if(s[i]==0){get(lst+1,i-1);lst=i;}
    get(lst+1,n);
    if(b1<c2){
        int ct=c2-b1;
        for(int i=0;i<ct;i++){
            ban[pc2[i]]=1,cnt[0]--;
        }
    }
    lst=-1;int nn=0;
    for(int i=1;i<=n;i++)if(!ban[i]){
        if(lst!=s[i])lst=s[i], s[++nn]=s[i];
    }n=nn;
    cnt[0]=cnt[1]=cnt[2]=0;
    for(int i=1;i<=n;i++)cnt[s[i]]++;
    memset(ban,0,sizeof(ban));
    lst=0;
    for(int i=1;i<=n;i++)
        if(s[i]==0){Sol(lst+1,i-1);lst=i;}
    Sol(lst+1,n);
    lst=-1,nn=0;
    for(int i=1;i<=n;i++)if(!ban[i]){
        if(lst!=s[i])lst=s[i], s[++nn]=s[i];
    }n=nn;
    cnt[0]=cnt[1]=cnt[2]=0;
    for(int i=1;i<=n;i++)cnt[s[i]]++;
    memset(ban,0,sizeof(ban));
    now=cnt[1],tar=cnt[0];
    lst=0;
    for(int i=1;i<=n;i++)
        if(s[i]==0){Sol2(lst+1,i-1);lst=i;}
    Sol2(lst+1,n);
    for(int i=1;i<=n;i++){
        if(!ban[i])printf("%c",'A'+p[s[i]]);
    }
}

AGC 036E ABC String

标签:cpp   bit   证明   set   ret   void   get   i++   一个   

原文地址:https://www.cnblogs.com/weiyanpeng/p/11407993.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!