首页 > 其他分享 >NFLS NOI模拟 Mizuki 与进化

NFLS NOI模拟 Mizuki 与进化

时间:2024-05-09 23:13:47浏览次数:20  
标签:cnt Mizuki 匹配 NOI BC AC NFLS AB ptr

涉及知识点:贪心,疑似Ad_hoc

题意

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

思路

A B C 的个数分别为 \(a,b,c\),为 AB AC BC 的子序列个数分别为 \(cnt_{AB},cnt_{AC},cnt_{BC}\),那么有如下等式:

\[\large\left\{ \begin{array}{c} a=cnt_{AB}+cnt_{AC}\\ b=cnt_{AB}+cnt_{BC}\\ c=cnt_{AC}+cnt_{BC} \end{array} \right. \]

经过简单演算可以得到:

\[\large\left\{ \begin{array}{c} cnt_{AB}=\frac{a+b-c}{2}\\ cnt_{AC}=\frac{a-b+c}{2}\\ cnt_{BC}=\frac{-a+b+c}{2} \end{array} \right. \]

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

接下来我们让前 \(cnt_{BC}\) 个 B 去匹配它右边离它最近的 C;然后让剩下 \(cnt_AB\) 个 B 去匹配它左边离它最近的 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;
}

标签:cnt,Mizuki,匹配,NOI,BC,AC,NFLS,AB,ptr
From: https://www.cnblogs.com/SkyNet-PKN/p/18183281

相关文章

  • NFLS NOI模拟 大战波特
    涉及知识点:贪心前言思维难度不高,就是挺好玩的,随手记录下有意思的贪心,奇妙的贪心经常比复杂的DP还有意思。题意打Boss,总共可以打\(n\(\leq10^6)\)回合,每回合可以普攻一次,造成\(x\)点伤害,每回合可以使用咒语,总共最多使用\(k\)次,使得Boss赋予一层“中毒”效果,并减弱......
  • 洛谷 P1031 [NOIP2002 提高组] 均分纸牌 题解
    题目简述有$N$堆纸牌,编号分别为$1,2,\ldots,N$。每堆上有若干张,但纸牌总数必为$N$的倍数。可以在任一堆上取若干张纸牌,然后移动。移牌规则为:在编号为$1$堆上取的纸牌,只能移到编号为$2$的堆上;在编号为$N$的堆上取的纸牌,只能移到编号为$N-1$的堆上;其他堆上取的纸牌,可......
  • 洛谷 P1012 [NOIP1998 提高组] 拼数 题解
    题目简述设有$n$个正整数$a_1\dotsa_n$,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。题目分析定义设$X$为数字$x$的字符串形式。$A+B$表示字符串$A$和字符串$B$相连组成的字符串。思路既然要构造最优解,显然如果有不优的情况的话,就需要对序列进行......
  • P3193 [HNOI2008] GT考试 题解
    之前学矩阵乘的时候做的题,当时因为不会\(kmp\)搜索一稀里糊涂过去了,现在填个坑。头图是\(Logos\)!P3193[HNOI2008]GT考试题链:洛谷题库题目大意:求有多少个长度为\(n\)的数字串的子串中不包含给出的长度为\(m\)位的串,范围\(n<=1e9\),$m<=20$。思路:首先考虑DP,令\(......
  • 初三下——NOIP 模拟赛(6~10)
    6ConclusionT1注意到一次碰撞后下一次一定不会碰到,一直这样直到出去。二分找位置即可然后算一下贡献。T2dp部分重排过后肯定是0+01+1的形式。于是根据这个dp。上面的dp冗余在其对于段数枚举了分界点。于是我们考虑就对于当前这个元素\(i\)进行单独考虑。记录是......
  • 洛谷P2375 [NOI2014] 动物园
    动物园题目描述输入格式输出格式输入输出样例输入3aaaaaababcababc输出36132开始时都没看出来这是kmp板子题先看看AC代码吧#include<bits/stdc++.h>#definelllonglongusingnamespacestd;constintmaxn=1e6+10;constintmod=1e9+7;chara[maxn];in......
  • 初三下——NOIP 模拟赛(1~5)
    R1rk10-。220pts。T23都读错题。浪费了将近60分钟。改。T2对于组合的掌握仍然不够熟练。找规律考虑每个点的贡献,应该使用0/1,而不是原数。转化过后可以在01矩阵上找规律了。(现在还是没搞懂那个原理)=》组合\((i,j)\bmod2=1\),当前仅当j在二进制下是i的子集,根据......
  • P1028 [NOIP2001 普及组] 数的计算
    题目链接:观察样例。当输入\(n=6\)时,6本身算一个。当6后加的数为1时只有一个。6后加的数为2时有62,621两个。6后加的数为3时有63、631两个。可以看到,我们往\(n\)后加的每一个不超过\(\dfrac{n}{2}\)的数都可以继续延伸。考虑递推。\(f[i]\)表示以\(i......
  • 初三下——NOIP 模拟赛(1~5)
    R1rk10-。220pts。T23都读错题。浪费了将近60分钟。改。T2对于组合的掌握仍然不够熟练。找规律考虑每个点的贡献,应该使用0/1,而不是原数。转化过后可以在01矩阵上找规律了。(现在还是没搞懂那个原理)=》组合\((i,j)\bmod2=1\),当前仅当j在二进制下是i的子集,根据......
  • P1010 [NOIP1998 普及组] 幂次方
    题目:P1010[NOIP1998普及组]幂次方[NOIP1998普及组]幂次方题目描述任何一个正整数都可以用2的幂次方表示。例如137=27+23+2^0。同时约定次方用括号来表示,即a^b可表示为a(b)。由此可知,137可表示为2(7)+2(3)+2(0)进一步:$7=22+2+20(2^1用2表示),并且3=2+2^......