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;
}