AC 反悔贪心,priority 难

19 篇文章 0 订阅
4 篇文章 0 订阅

LINK

题目

在这里插入图片描述
示例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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值