CF1560 E. Polycarp and String Transformation(思维 枚举)

E. Polycarp and String Transformation

点击跳转

题意:

假设有一个字符串 s s s,字符串 t t t开始为空;
每次执行一个过程,第一步是另 t = t + s t=t+s t=t+s,第二步是删去 s s s中的全部的某字母。
重复执行两个步骤,直到 s s s为空。
现在给出 t t t串,输出 s s s串和对应的字母删除顺序。

思路:

  • 赛时一直有几个细节没想好,赛后看了代码才想明白;
  • 记录每个字符出现的最后位置,最后删除的字母,出现的最后位置越大。以此为排序标准,可以得到删除的字符顺序;
  • 这样就得到了每个字母是第几个被删除的,记作 p o s i pos_i posi
  • 如何确定 s s s的长度呢?
  • 对于任意一个字母 x x x来说,出现次数 c n t i cnt_i cnti除以 p o s i pos_i posi就是 s s s中该字母的出现次数 t o t tot tot
  • 因为在该字母 x x x被删除前,每个过程出现的次数都是 t o t tot tot;在该字母 x x x被删除后,每个过程出现的次数都是 0 0 0
  • 所以如果 c n t i % p o s i ! = 0 cnt_i\%pos_i!=0 cnti%posi!=0的话,一定不是合法的 t t t串,也就无法还原除 s s s,输出 − 1 -1 1;
  • 这样枚举一遍每个字母就能得到 s s s的长度 l e n len len了,只需要截取 t t t l e n len len长度的前缀就是 s s s了;
  • 上面只是检验了出现字母的个数,还没有检验具体的顺序;
  • 如果从 s s s能够再得到 t t t,才说明 s s s是合法的答案,所以要再 c h e c k check check一遍。

代码:


int cnt[30];//表示每个字母的出现次数
int las[30];//表示每个字母最后一次出现的位置 
int pos[30];///表示每个字母是第几个被删除的 

bool cmp(char a,char b){//删除字符排序的话肯定是出现位置下标越大说明删除的越晚 
	return las[a-'a']<las[b-'a'];
}

int main(){
	int _=read;
	while(_--){
		string t;cin>>t;
		memset(las,-1,sizeof las);//初始化 
		memset(cnt,0,sizeof cnt);//清空 
		for(int i=0;t[i];i++){
			int x=t[i]-'a';
			cnt[x]++;//记录每个字母出现的次数 
			las[x]=i;//更新每个字母的最大下标位置 
		}
		string del="";
		for(int i=0;i<26;i++){
			if(las[i]!=-1) del+='a'+i;//出现过的字母都删除 
		}
		sort(del.begin(),del.end(),cmp);//排序 
		memset(pos,0,sizeof pos);
		for(int i=0;i<del.size();i++){
			pos[del[i]-'a']=i+1;//记录是第几个被删的 
		}
		int len=0,flag=1;
		for(int i=0;i<26;i++){
			if(cnt[i]==0) continue;
			if(cnt[i]%pos[i]){//不整除的话不符合题意 
				flag=0;
				break;
			}
			len=len+cnt[i]/pos[i];//记录这个字母在s中的次数 
		}
		string s=t.substr(0,len);//s 
		string tmp="";//从s倒推一遍看是否和t相同 
		for(int i=1;i<=del.size();i++){
			for(int j=0;j<len;j++){
				if(pos[s[j]-'a']>=i){//删除时间>=i说明该字母还没有被删除 
					tmp+=s[j];
				}
			}
		}
		if(tmp!=t) flag=0;
		if(flag) cout<<s<<" "<<del<<endl;
		else puts("-1");	
	} 
	
	
	
	return 0;
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆沙睡不醒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值