Loading

cf2111e

CF2111E Changing the String

link

题意

给定仅由 \(abc\) 构成的字符串,\(q\) 次操作可以将串中任意一个 \(x\) 修改为 \(y\),可以选任意操作不做,使得字符串字典序最小。\(\sum n,q \leq 2\times 10^5,s_i,x,y\in \{a,b,c\}\)

题解

字典序最小显然是从前往后贪心。由于字符集很小,直接分类讨论。

  • \(s_i=a\),啥都不需要干。
  • \(s_i=b\),考虑 \(b\rightarrow a\),如果有这种操作就执行。还有可能是 \(b\rightarrow c\rightarrow a\),先看 \(b\rightarrow c\),在 \(c\rightarrow a\) 中选第一个比 \(b\rightarrow c\) 大的。
  • \(s_i=c\),考虑 \(c\rightarrow b\)\(a\),这种直接做。还有 \(c\rightarrow b\rightarrow a\),和上一种一样。
    各种操作可以 set 维护。复杂度 \(O((n+q)\log q)\)aclink

  • 代码好写。

代码

#include<bits/stdc++.h>
#define i64 long long
#define L(a,b,c,d) for(int a=b;a<=c;a+=d)
#define R(a,b,c,d) for(int a=b;a>=c;a-=d)

using namespace std;
const int N=2e5+5;

void solve();
int n,q;
set<int> ba,bc,ca,cb;
char s[N];

signed main(){
  int Test=1;
  scanf("%d",&Test);
  while(Test--) solve();
  return 0;
}

void solve(){
  scanf("%d%d",&n,&q);
  scanf("%s",s+1);
  ba.clear(),bc.clear(),ca.clear(),cb.clear();
  L(i,1,q,1){
    char p[2],q[2];
    scanf("%s%s",p,q);
    if(p[0]=='b'){
      if(q[0]=='a') ba.insert(i);
      else if(q[0]=='c') bc.insert(i);
    }
    else if(p[0]=='c'){
      if(q[0]=='a') ca.insert(i);
      else if(q[0]=='b') cb.insert(i);
    }
  }
  L(i,1,n,1){
    if(s[i]=='b'){
      if(!ba.empty()){
        s[i]='a';
        ba.erase(ba.begin());
      }
      else if(!bc.empty()){
        auto it=ca.upper_bound(*bc.begin());
        if(it!=ca.end()){
          bc.erase(bc.begin());
          ca.erase(it);
          s[i]='a';
        }
      }
    }
    else if(s[i]=='c'){
      if(!ca.empty()){
        s[i]='a';
        ca.erase(ca.begin());
      }
      else if(!cb.empty()){
        auto it=ba.upper_bound(*cb.begin());
        if(it!=ba.end()){
          cb.erase(cb.begin());
          ba.erase(it);
          s[i]='a';
        }
        else{
          s[i]='b';
          cb.erase(cb.begin());
        }
      }
    }
  }
  printf("%s\n",s+1);
}
posted @ 2025-08-27 17:10  jess1ca1o0g3  阅读(6)  评论(0)    收藏  举报