A AC
题意:
给你一个长度为n的字符串,你最多修改k次,问你字符串中最多能有多少个ac。
并要求你输出修改后的字符串。
思路:
让c[i]代表将str[i]变成'a',str[i+1]变成'c'所需要的最小花费。
然后问题变成了在花费不超过k的情况下,最多可以选择多少个互不相邻的位置i。
此时如果不考虑输出修改后的字符串,问题就变成了一个典型的反悔贪心问题。
用堆维护实现。
然后字符串的输出发现也可以利用上面代码上的 l数组,r数组维护。
就是每个区间(l[i],r[i])都变成了很多个 'ac' 。
此时这个问题就解决了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+15;
typedef long long ll;
ll n,m,a[N],vis[N],l[N],r[N],pl[N],pr[N],mp[N];
char str[N];
struct node{
int id,val;
bool operator < (const node &b) const{
return val>b.val;
}
};
priority_queue<node>q;
void solve()
{
ll cnt=0,w=0;
node tp,nd;
pl[0]=pr[0]=0;
pl[n]=pr[n]=n;
for(int i=1;i<=n-1;i++)
{
tp.id=i;
l[i]=i-1; r[i]=i+1;
pl[i]=i; pr[i]=i;
tp.val=a[i]=(str[i]!='a')+(str[i+1]!='c');
q.push(tp);
}
r[0]=1; l[n+1]=n;
l[n]=n-1; r[n]=n+1;
a[0]=a[n]=112345678;
while(!q.empty())
{
tp=q.top();
int id=tp.id,v=tp.val;
if(vis[id]){
q.pop(); continue;
}
if(w+v>m)
break;
q.pop();
cnt++; w+=v;
mp[id]=1; vis[l[id]]=vis[r[id]]=1;
nd.val=a[l[id]]+a[r[id]]-a[id];
pl[id]=pl[l[id]]; pr[id]=pr[r[id]];
l[id]=l[l[id]]; r[l[id]]=id;
r[id]=r[r[id]]; l[r[id]]=id;
nd.id=id;
a[id]=nd.val;
q.push(nd);
}
cout<<cnt<<endl;
for(int i=1;i<=n;i++)
{
if(mp[i]&&!vis[i])
for(int j=pl[i]+1;j+1<=pr[i]&&j+1<=n;j+=2)
{
str[j]='a'; str[j+1]='c';
}
}
cout<<(str+1)<<endl;
}
int main()
{
cin>>n>>m;
scanf("%s",str+1);
solve();
return 0;
}