CF2111E
首先可以把所有操作的类型及时间记录下来,分类存进 map 里。
根据贪心,显然越靠前的字母越小越好。从前往后考虑每位 \(s_i\):
- \(s_i=a\) 已经最优了,无需处理。
- \(s_i=b\) 优先考虑 \(b \rightarrow a\),如果不存在这样的操作就考虑 \(b \rightarrow c \rightarrow a\)(先找 \(b \rightarrow c\) 是否存在,存在则取时间最早的,并在 \(c\rightarrow a\) 中找到第一个时间在它后面的,若能找到则更新,并同时删除两个操作)。
- \(s_i=c\) 优先考虑 \(c \rightarrow a\),如果不存在则考虑 \(c\rightarrow b\rightarrow a\)(先找 \(c \rightarrow b\) 是否存在,存在则取时间最早的,\(s_i\leftarrow b\),并在 \(b\rightarrow a\) 中找第一个时间在它后面的,此时再删除第一步的操作。若能找到则更新为 \(a\),并删除该操作)。
注意实现时一定要先查找完再删除对应的迭代器,否则会因迭代器无效而导致 RE。
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
map<int,int> ba,bc,ca,cb;
string s;
int n,m;
char x,y;
void solve(){
ba.clear();bc.clear();ca.clear();cb.clear();
cin>>n>>m;
cin>>s;
for(int i=1;i<=m;i++){
cin>>x>>y;
if(x=='b'&&y=='a')ba[i]=i;
if(x=='b'&&y=='c')bc[i]=i;
if(x=='c'&&y=='b')cb[i]=i;
if(x=='c'&&y=='a')ca[i]=i;
}
for(int i=0;i<n;i++){
// cout<<i<<endl;
if(s[i]=='a')continue;
if(s[i]=='b'){
if(ba.size()){
auto it=ba.begin();
ba.erase(it);
s[i]='a';
}
else if(bc.size()){
auto it=bc.begin();
auto it1=ca.upper_bound(it->second);
if(it1!=ca.end()){
s[i]='a';
bc.erase(it);
ca.erase(it1);
}
}
}
if(s[i]=='c'){
if(ca.size()){
auto it=ca.begin();
ca.erase(it);
s[i]='a';
}
else if(cb.size()){
auto it=cb.begin();
s[i]='b';
auto it1=ba.upper_bound(it->second);
cb.erase(it);//必须先查找再删迭代器,否则 it 指向的迭代器无效会发生 Runtime Error。或者记录迭代器对应的值也可以
if(it1!=ba.end()){
s[i]='a';
ba.erase(it1);
}
}
}
}
cout<<s<<'\n';
return;
}
int main(){
int T;
cin>>T;
while(T--)
solve();
return 0;
}

浙公网安备 33010602011771号