CF1560E 每日一题 Polycarp and String Transformation

题目链接:Problem - E - Codeforces

input:

7
abacabaaacaac
nowyouknowthat
polycarppoycarppoyarppyarppyrpprppp
isi
everywherevrywhrvryhrvrhrvhv
haaha
qweqeewew

output:

abacaba bac
-1
polycarp lcoayrp
is si
everywhere ewyrhv
-1
-1

题意:

现有字符串 s ,以及空字符串 t ,现在对这两个字符串重复做如下操作,直至 s 为空串:

1.首先另 t = t + s ,也就是说将当前的 s 拼接到 t 的右边。

2.随后删除 s 中的任意一类字符。比如当前 s = aabcbaa ,删除 b 后变为:aacaa。

现在直接给出字符串 t ,试给出可能的初始 s 以及删除字符的顺序(答案不唯一,输出任意一种即可),若无解,输出 -1。

思路:

比较好处理的是删除字符的顺序,这个序列一定是唯一的。我们观察所有字符最后一次出现的位置,按下标从小到大排序,即为删除顺序。

现在要处理的是初始串 s 。可以枚举 t 的前缀,然后对每一种前缀,模拟完整的操作过程,最后判断生成的字符串是否等于 t。这种暴力显然会超时,所以我们需要对大量的不可能通向答案的前缀进行剪枝。这里引入一个巧妙的思维。对于某一个字符,若其在第 k 轮删除,那么其本身以及其加入字符串 t 右端的数量为 k + 1.我们可以利用这个来判断某一个前缀最终生成的串的长度。如果长度等于 t 的长度,那么该前缀有可能为正解,可以进一步模拟过程并判断,如果长度大于 t 的长度,那么该前缀以及更长的前缀生成序列长度一定大于 t ,所以问题无解。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define endl "\n"
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int mod=1e9+7;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

int tt,n;
string t,lst;
bool vis[30];

bool func(string s)
{
	string ss=s;
	for(int i=0;i<lst.size();i++)
	{
		for(int j=0;j<s.size();j++)
		{
			if(s[j]=='!')
			{
				continue;
			}
			if(s[j]==lst[i])
			{
				s[j]='!';
			}
			else
			{
				ss+=s[j];
			}
		}
	}
	if(ss==t)
	{
		return 1;
	}
	return 0;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>tt;
	while(tt--)
	{
		cin>>t;
		n=t.length();	
		memset(vis,0,sizeof vis);
		lst="";
		for(int i=n-1;i>=0;i--)
		{
			if(!vis[t[i]-'a'])
			{
				lst+=t[i];
				vis[t[i]-'a']=1;	
			}
		}
		reverse(lst.begin(),lst.end());
		map<char,int> mp;
		for(int i=0;i<lst.length();i++)
		{
			mp[lst[i]]=i+1;
		}
		bool f=0;
		string s="";
		int stime=0;
		for(int i=0;i<t.size();i++)
		{
			s+=t[i];
			stime+=mp[t[i]];
			if(stime>t.size())
			{
				break;
			}
			if(stime==t.size())
			{
				if(func(s))
				{
					f=1;
					break;
				}
			}
		}
		if(!f)
			cout<<-1<<endl;
		else
			cout<<s<<" "<<lst<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值