题意:
给你n个初始字符串~
,再给你n个最终字符串
~
,问能不能找到两个字符串S和T,按照以下操作后,使得初始字符串和最终字符串一一对应相同,也就是对于所有的i,都满足
(输入保证长度对应相同,且一定存在一行字符串,初始和最终不同)
操作:对于每个串,从左往右找到第一个子串S,将其替换成T,找不到就不进行修改
思路:
先随便找一个不满足的字符串
,那么可以修改
的一段尽可能短的前缀使得
,也就是可以暂时将当前的S和T作为答案,其中S是
的一段前缀,T是
的一段前缀,且|S| = |T|
然后只要依次检测的所有字符串按照以上操作能否全部满足即可
如果某个字符串无法修改成一致( 利用当前S和T按照上述操作后不能满足
),那么有三种情况:
和
本相同,但是修改之后反而不同了
和
不同,然而
并不包含子串S,但是
包含子串S的一段后缀,且修改这段后缀即可满足
和
不同,不仅
不包含子串S,
也不包含子串S的任何一段后缀,或者说修改了也仍然不可能满足
对于情况③,找到直接就是NO了,没有任何办法,例如题目中的第三个样例
对于情况②,很显然可以将S和T同时去掉一段前缀,使得满足操作后,例如下面这个样例,正确答案应该是S = "bc",T = "bd"
2
abcpp
kbcpp
abdpp
kbdpp
对于情况③,可以将S和T的后面同时多加几个字母, 使得满足操作后,其中多加的字母很显然是固定的,例如下面这个样例,如果S = "abc",T = "aba",那么会修改到第2个字符串,所以答案应该是S = "abcd",T = "abad"
2
abcd
abc
abad
abc
那么这题其实就可以搞定了,步骤如下
- 先单独检测一遍情况②,如果出现,暴力删除当前S和T的第一个字母直到满足条件为止,如果在删除某个字母之后前面某个字符串反而不能满足操作后
了,直接输出NO,结束
- 然后单独检测一遍情况①,如果出现, 暴力在S和T后面多接一个字母直到满足条件为止,如果在添加某个字母之后前面某个字符串反而不能满足操作后
了,直接输出NO,结束
- 最后再检测一遍情况③,出现直接就是NO
- YES,输出S和T
以上操作都可以在O(len)的复杂度内解决,其中len为所有字符串总长度,中间可能需要KMP
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
typedef struct Res
{
int len, L, R, l, r;
int net[3005];
char s1[3005], s2[3005];
void Getnext()
{
int i, j;
i = l, j = l-1;
net[l] = l-1;
while(i<=r)
{
if(j==l-1 || s1[i]==s1[j])
{
i++, j++;
if(s1[i]==s1[j])
net[i] = net[j];
else
net[i] = j;
}
else
j = net[j];
}
}
}Res;
Res a[3005], poi;
int Jud(Res c, Res d)
{
int i, j, k, now, flag;
char temp[3005];
for(i=1;i<=c.len;i++)
temp[i] = c.s1[i];
temp[c.len+1] = flag = 0;
i = 1, j = poi.l;
while(i<=c.len)
{
if(temp[i]==poi.s1[j])
{
if(j==poi.r)
{
k = i-(poi.r-poi.l);
for(now=poi.l;now<=poi.r;now++)
temp[k++] = poi.s2[now];
flag = 1;
break;
}
i++, j++;
}
else
{
j = poi.net[j];
if(j==poi.l-1)
i++, j = poi.l;
}
}
//printf("%s %s\n", temp+1, c.s2+1);
if(strcmp(temp+1, c.s2+1)==0)
return 1; //一样
if(flag)
return -1; //修改过,但还是不一样
return 0; //没有被修改,不一样
}
int main(void)
{
int n, i, now;
scanf("%d", &n);
for(i=1;i<=n;i++)
{
scanf("%s", a[i].s1+1);
a[i].len = strlen(a[i].s1+1);
}
for(i=1;i<=n;i++)
scanf("%s", a[i].s2+1);
for(i=1;i<=n;i++)
{
if(strcmp(a[i].s1+1, a[i].s2+1)!=0)
{
swap(a[1], a[i]);
break;
}
}
poi = a[1];
for(i=a[1].len;i>=1;i--)
{
if(poi.s1[i]!=poi.s2[i])
poi.L = i;
}
for(i=1;i<=poi.len;i++)
{
if(poi.s1[i]!=poi.s2[i])
poi.R = i;
}
poi.l = 1, poi.r = poi.R;
poi.Getnext();
for(i=1;i<=n;i++)
{
now = Jud(a[i], poi);
while(now!=1 && poi.l!=poi.L)
{
if(now==0)
{
poi.l++;
poi.Getnext();
now = Jud(a[i], poi);
}
else
break;
}
}
for(i=1;i<=n;i++)
{
now = Jud(a[i], poi);
while(now!=1 && poi.r!=poi.len)
{
if(now==-1)
{
poi.r++;
poi.Getnext();
now = Jud(a[i], poi);
}
else
break;
}
}
for(i=1;i<=n;i++)
{
if(Jud(a[i], poi)!=1)
{
printf("NO\n");
return 0;
}
}
printf("YES\n");
for(i=poi.l;i<=poi.r;i++)
printf("%c", poi.s1[i]);
puts("");
for(i=poi.l;i<=poi.r;i++)
printf("%c", poi.s2[i]);
puts("");
return 0;
}