【题目】http://codeforces.com/contest/1029/problem/A
【题意】给出子串t和子串出现的次数k,求最短的父串s
【思路】每次加上子串,看结尾是不是子串的前缀,是的话补全子串,操作直到k。
【代码】
AC代码:
#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=2500+5;
const int inf=1e9+5;
char a[M];
char b[M];
int main()
{
int n,k;
cin>>n>>k;
cin>>a;
if(n!=1)
{
k--;
int p;
strcpy(b,a);
while(k--)
{
//只要每次从父串尾巴找到子串的前缀补全即可
int flag=1;
for(int i=strlen(b)-n+1; i<strlen(b); i++)
{
flag=0;
for(int j=0,k=i; k<strlen(b); j++,k++)
{
if(b[k]!=a[j])
{
flag=1;
break;
}
p=j;
}
if(flag==0)
break;
}
if(flag==0)
{
for(int j=p+1,k=strlen(b); j<n; j++,k++)
{
b[k]=a[j];
}
}
else
{
strcat(b,a);
}
}
cout<<b<<endl;
}
else
{
for(int i=0; i<k; i++)
cout<<a;
}
return 0;
}
NC代码:
#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=2500+5;
const int inf=1e9+5;
char a[M];
char b[M];
int main()
{
int n,k;
cin>>n>>k;
cin>>a;
if(n!=1)
{
k--;
int flag=0, flag2=0;
int head=0,headt=0,fh=0;
strcpy(b,a);
//求fh(下1次头要跳多远)
//从i=1往后(跳过i=0)找子串出现的位置
for(int i=1; i<strlen(b); i++)//枚举开头
{
flag=0;
for(int j=0,k=i; k<strlen(b); k++,j++)//枚举子串每1位
{
//k<父串长度能控制结尾是因为
//父串一定从只剩最长1个子串长度的地方开始枚举
fuck(j);
if(b[k]!=a[j])//如果不满足就要退出,换i再做
{
flag2=0;
flag=1;
fh=0;
break;
}
if(flag2==0)//f2让只有子串匹配位置的开头能改变fh
{
flag2=1;
fh=k;
}
}
if(flag==0)//flag为0代表当前情况找到了子串
break;
}
if(fh==0)
fh=strlen(b);
fuck(fh);
while(k--)
{
int len=strlen(b);
flag=0,flag2=0;
head=headt;//headt在上一次循环中被改变
int p;
for(int i=head+1; i<len; i++)
//下1次寻找从上1次匹配成功的下1位开始找
{
flag=0;
for(int j=0,k=i; k<len; k++,j++)
{
if(b[k]!=a[j])
{
flag2=0;
flag=1;
headt=head+fh;//子串没有循环的话,下1个head当然是head+fh
break;
}
if(flag2==0)
{
flag2=1;
headt=k;//否则head就是匹配的开始位置
}
p=j;//存还没有补到父串上的剩余子串断点
}
if(flag==0)//flag是0代表匹配到了位置
break;
}
if(flag==0)//补全父串
{
for(int j=p+1,k=len; j<n; j++,k++)
{
b[k]=a[j];
}
}
else//没找着就直接加上
{
strcat(b,a);
}
}
cout<<b<<endl;
}
else
{
for(int i=0; i<k; i++)
cout<<a;
}
return 0;
}