问题描述
ZYB获得了一个神秘的非空字符串𝑝。
初始时,串𝑆是空的。
ZYB会执行若干次这样的操作:
- 选取𝑆中的一个任意的位置(可以是最前面或者最后面)
- 在这个位置上插入一个完整的𝑝,得到一个新的𝑆。
但是ZYB不小心把𝑝弄丢了。
他告诉你现在的𝑆是什么,请帮他还原出可能的𝑝。
如果有多个𝑝符合要求,选取长度最短的。
如果仍然有多解,选取字典序最小的。
输入格式
从文件string.in中读入数据。
这道题有多组数据,第一行一个数𝑇,表示数据组数。
对于每组数据,读入一行字符串,表示𝑆。
输出格式
输出到文件string.out中。
一共𝑇行,每行一个字符串𝑝,表示对应的答案。
样例
样例输入
1
hhehellolloelhellolo
样例输出
hello
样例解释
𝑆 为:
1.
2. hello
3. hhelloello
4. hhelloelhellolo
5. hhehellolloelhellolo
6.
数据规模与约定
前20% :|𝑆| ≤ 8
前40% :|𝑆| ≤ 20
前60% :|𝑆| ≤ 100,
Σ︀
|𝑆| ≤ 300
另有10% :𝑆是𝑝等概率插入可行位置构造出来的。
另有10% :𝑝的长度不超过3。
100% :|𝑆| ≤ 200, 𝑇 ≤ 10,
Σ︀|𝑆| ≤ 666
题解:
看到数据这么小,就可以知道枚举计算。
但枚举一个len,一个左端点,就是n^2了,再加上递归枚举删除的字串,这是我们不能接受的。
所以考虑优化判断。
可以发现,对区间的判断是可以合并的。这启发我们用区间dp
但是怎么求呢????
考虑题目中的过程,模拟一下,退而求其次,可以考虑对加入的字符(已判断的长度)作为阶段。
这样的话设
f[l][i][j]为已经判断长l时,i到j是否合法。
注意此处的合法指的是是否能被枚举的字串构造,若不能也得保证多余的恰好是字串的前缀。
又发现可以省去l这一维
这时,更新阶段即为f[i][j]=f[i][j-1]&(a[j]==b[l]);
状态合并&转移有多种可能。但对于此题来说,因为我们的便利顺序在末尾增添字符,且这道题的合法合并是必定有一方是字串长度的整数倍,所以
f[i][j] | =f[i][j-len
×
\times
×k] & f[j-len
×
\times
×k+1][j];
end
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#define N 205
using namespace std;
int f[N][N];
map<string, int> hs;
int n;
char a[N],b[N];
int all[N],tem[N],rest[N];
inline int check(int len){
memset(f,0,sizeof(f));
for(int i=1;i<=n;++i){
f[i][i-1]=1;f[i][i]=a[i]==b[1];
}
for(int l=2;l<=n;++l){
char c=b[(l-1)%len+1];
for(int i=1;i<=n-l+1;++i){
int j=i+l-1;
f[i][j]=f[i][j-1]&(a[j]==c);
for(int k=1;!f[i][j]&&k*len<=l;++k){
f[i][j]|=f[i][j-len*k]&f[j-len*k+1][j];
}
}
}
return f[1][n];
}
void work(){
scanf("%s",1+a);
n=strlen(a+1);
// cout<<n<<endl;
memset(all,0,sizeof(all));
string best;int found=0;
for(int i=1;i<=n;++i)all[a[i]-'a'+1]++;
/*for(int i=1;i<=n;++i)cout<<a[i];
cout<<endl;*/
for(int len=1;len<=n;++len)if(n%len==0){
hs.clear();
int num=n/len;
int flag=1;
for(int i=1;i<=26;++i){
//if(len==5)cout<<all[i]<<endl;
if(all[i]%num!=0){flag=0;break;}
tem[i]=all[i]/num;
}
// cout<<len<<endl;
if(!flag)continue;
for(int i=1;i<=n-len+1;++i){
memcpy(rest,tem,sizeof(tem));
flag=1;
for(int j=0;j<len;++j){
b[1+j]=a[i+j];
if(--rest[b[1+j]-'a'+1]<0){flag=0;break;}
}
if(flag==0)continue;
b[1+len]=0;///
string cur=b+1;
// cout<<len<<endl;
if(hs.find(cur)!=hs.end())continue;
hs.insert(make_pair(cur,len+i));
// if(len==5&&cur=="hello")cout<<check(len)<<endl;
if(check(len)){
if(found==0)best=cur;
else best=min(best,cur);
found=1;
}
}
if(found)break;
}
//string cur="hello";
// best=min(cur,best);
//cout<<found<<endl;
cout<<best<<endl;
return ;
}
int main(){
int t;cin>>t;
while(t--){
work();
}
return 0;
}