题目
示例1
输入
9 2
arakbacca
输出
3
acacbacca
翻译:
给一个长度为 n 的字符串, 最多有 k 次修改字符串的机会, 每一次只能将任意一位字符修改为其他字符, 输出修改后的字符串最多有多少个"ac", 并输出字符串
思路
能想到这个思路就很NB!!!
此题和种树有很大的关系,都用到了缩点,更难的一点是需要另开两个数组标记一下改变的位置。
具体解说用一个例子稍作解释:
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e5+10;
const int inf=0x3f3f3f3f;
struct node{
int a,pos;
//priority_queue中自定义的比较函数的效果和sort()是相反的
bool operator < (const node &x) const{
return a>x.a;
}
};
priority_queue<node>q;//从小到大排序
char s[N];
int l[N],r[N];//记录左右位置
int pl[N],pr[N];//pl[i]:记录字符串以i为中心修改为ac的左位置/另一边同理
//为区间(pl[i],pr[i]]
bool vis[N],mp[N];//vis:记录是否被缩点 mp:记录是否为缩点的中心点
ll ans,num;//记录ac数目 记录修改个数
int a[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,k;cin>>n>>k;
cin>>s+1;
for(int i=1;i<n;i++){
a[i]=(s[i]!='a')+(s[i+1]!='c');//修改1/2个位置
pl[i]=pr[i]=i;
l[i]=i-1,r[i]=i+1;//记录左右位置
q.push({a[i],i});
}
pl[n]=pr[n]=n;
a[n]=a[0]=inf;//取一个较大值,不修改0和n+1位置
while(!q.empty()){
int pos=q.top().pos;//此点的位置
q.pop();
if(vis[pos])continue;//被标记过 不再处理
if(num+a[pos]>k)break;//修改次数超限
ans++;//"ac"个数
num+=a[pos];//修改字母数
a[pos]=a[l[pos]]+a[r[pos]]-a[pos];//把此位置的值改变,为另一种选择
vis[l[pos]]=vis[r[pos]]=mp[pos]=1;//标记
pl[pos]=pl[l[pos]];pr[pos]=pr[r[pos]];//记录此区间(pl[pos],pr[pos]]均为"ac"串
cout<<"ll="<<pl[pos]<<" rr="<<pr[pos]<<endl;
//缩点
l[pos]=l[l[pos]];r[l[pos]]=pos;
r[pos]=r[r[pos]];l[r[pos]]=pos;
q.push({a[pos],pos});
}
cout<<ans<<endl;
for(int i=1;i<=n;i++){
if(mp[i]&& !vis[i]){
for(int j=pl[i]+1;j<pr[i]&&j<n;j+=2)
s[j]='a',s[j+1]='c';
}
}
cout<<s+1;
return 0;
}