HDOJ 4300 Clairewd’s message
题目大意
给你一个字母表(密钥) , 给你一个字符串。这个字符串前部分是明文,后部分是密文,但不清楚从哪里分开,并且密文可能不完整。
举个例子,明文用X表示,密文用Y表示,那么完整的字符串应该是XXXYYY。然而题目给你XXXYY,问你从哪里断开。
题解:
我们先部分青红皂白地把整个串按照密钥翻译成T串,那么原串的后缀,T串的前缀是相等的,所以对S串求nex,T串求ext。枚举一个i,看ext[i] + i 是否大于等于长度n即可。
** **
#include<cstdio>
#include<cstring>
const int N = 1e5 + 100;
int n , ext[N] , nex[N] , T;
char table[26] , retab[26] , s[N] , t[N];
inline int max(int a, int b){return a > b ? a : b;}
void Getnext(char *s)
{
nex[0] = n , nex[1] = 0;
for(int &i = nex[1] ; i + 1 < n && s[i] == s[i + 1];++ i);
for(int i = 2 , po = 1; i < n;i ++)
if(i + nex[i - po] > po + nex[po])
{
int j = po + nex[po] - i;
for(j = max(0 , j); j + i < n && s[j] == s[i + j];++ j);
nex[po = i] = j;
}
else nex[i] = nex[i - po];
}
void exkmp(char *s,char *t)
{
ext[0] = 0;
for(int &i = ext[0];i < n && s[i] == t[i];++ i);
for(int i = 1 , po = 0; i < n;i ++)
if(i + nex[i - po] > po + ext[po])
{
int j = po + ext[po] - i;
for(j = max(0 , j);j + i < n && s[j] == s[i + j];j ++);
ext[po = i] = j;
}
else ext[i] = nex[i - po];
}
int main()
{
for(scanf("%d",&T) ; T ; T --)
{
scanf("%s",&table) , scanf("%s",&s) , n = strlen(s);
for(int i = 0;i < 26;i ++) retab[table[i] - 'a'] = i + 'a';
for(int i = 0;i < n;i ++) t[i] = retab[s[i] - 'a'];
Getnext(s) , exkmp(t , s);
int flag = 0;
for(int i = (n & 1) ? (n >> 1 | 1) : (n >> 1); i < n;i ++)
if(i+ext[i] >= n)
{
flag = 1;
for(int j = 0;j < i;j ++) printf("%c",s[j]);
for(int j = 0;j < i;j ++) printf("%c",retab[s[j]-'a']);
break;
}
if(!flag) printf("%s",s);
printf("\n");
}
return 0;
}