But my words, like sile|

MessageBoxA

园龄:4年10个月粉丝:4关注:0

2024-05-09 23:01阅读: 9评论: 0推荐: 0

NOI模拟 Mizuki 与进化

涉及知识点:贪心

题意

给你一个只包含 A B C 的长度为 2n 的字符串,问能否将该字符串划分为 n 个子序列,子序列只能是 AB AC BC 中的一个,或输出无解。

思路

A B C 的个数分别为 a,b,c,为 AB AC BC 的子序列个数分别为 cntAB,cntAC,cntBC,那么有如下等式:

{a=cntAB+cntACb=cntAB+cntBCc=cntAC+cntBC

经过简单演算可以得到:

{cntAB=a+bc2cntAC=ab+c2cntBC=a+b+c2

此时如果算出来 cnt 不是一个正整数说明无解。

接下来我们让前 cntBCB 去匹配它右边离它最近的 C;然后让剩下 cntABB 去匹配它左边离它最近的 A;最后再让剩下的 AC 两两匹配即可。匹配过程中如果匹配失败说明无解。

贪心正确性:

  1. 为什么 B 匹配右边离它最近的 C

    很明显,如果匹配更远的 C,有可能会抢了它左边的 B 本来可以匹配到的 C。匹配 B 的情况同理。

  2. 为什么前面的 B 去匹配 C,后面的 B 去匹配 A

    匹配 C 的肯定是越前面越好,匹配 A 的肯定是越后面越好,这样匹配才会使得最后 AC 的匹配更容易成功,可以假设交换发现一定不优。

代码

#include<bits/stdc++.h>
#define getmid int mid=(l+r)/2
using namespace std;
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
const int MAXN=2e5+5;
int n,bel[MAXN],cnt[3],cntab,cntbc;
bool vis[MAXN];
string s;
queue<int>q;
bool check_remain(){
    for(int i=1;i<=n;i++){
        if(s[i]=='B' && vis[i]==0) return false;
    }
    for(int i=1;i<=n;i++){
        if(vis[i]) continue;
        if(s[i]=='A') q.push(i);
        else if(q.empty()) return false;
        else bel[i]=q.front(),q.pop();
    }
    if(!q.empty()) return false;
    return true;
}
int main(){
    // freopen("evolution.in","r",stdin);
    // freopen("evolution.out","w",stdout);
    cin>>n>>s;n<<=1;
    if(s.front()=='C' || s.back()=='A'){puts("No");return 0;}
    s=" "+s;

    for(int i=1;i<=n;i++) cnt[s[i]-'A']++;
    if(cnt[0]+cnt[1]+cnt[2]==0){puts("No");return 0;}
    if((cnt[0]+cnt[1]-cnt[2]<0) || (cnt[0]+cnt[1]-cnt[2])&1){puts("No");return 0;}
    if((cnt[0]-cnt[1]+cnt[2]<0) || (cnt[0]-cnt[1]+cnt[2])&1){puts("No");return 0;}
    if((-cnt[0]+cnt[1]+cnt[2]<0) || (-cnt[0]+cnt[1]+cnt[2])&1){puts("No");return 0;}
    cntab=(cnt[0]+cnt[1]-cnt[2])/2;
    cntbc=(-cnt[0]+cnt[1]+cnt[2])/2;
    // cout<<cnt[0]<<' '<<cnt[1]<<' '<<cnt[2]<<' '<<cntab<<' '<<cntbc<<endl;
    
    int ptr,i;
    s[n+1]='C';
    for(i=1;i<=n && cntbc>0;i++){
        if(s[i]!='B') continue;
        vis[i]=1;

        ptr=i+1;
        while(vis[ptr] || s[ptr]!='C') ptr++;
        if(ptr>n){puts("No");return 0;}
        vis[ptr]=1;bel[ptr]=i;

        cntbc--;
    }
    int tmp=i;
    s[0]='A';
    for(i=n;i>=tmp && cntab>0;i--){
        if(s[i]!='B') continue;
        vis[i]=1;

        ptr=i-1;
        while(vis[ptr] || s[ptr]!='A') ptr--;
        if(ptr<0){puts("No");return 0;}
        vis[ptr]=1;bel[i]=ptr;
        
        cntab--;
    }
    if(!check_remain()) puts("No");
    else{
        puts("Yes");
        for(i=1;i<=n;i++){
            if(bel[i]) wt(bel[i],' '),wt(i,'\n');
        }
    }
    return 0;
}

本文作者:MessageBoxA

本文链接:https://www.cnblogs.com/SkyNet-PKN/p/18183281

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MessageBoxA  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 evening Corn Wave
  2. 2 Группа крови Кино
  3. 3 The Sound Of Silence Simon & Garfunkel
  4. 4 dB doll YUE.STEVEN
Группа крови - Кино
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.