题目链接:HDU-4300
题意:给你一个二十六位的密码表A,然后给你一段文字S。前面部分完整的是密文,
后面是未必完整的明文,让你输出完整的密文+完整的明文。
要求使得文字S最短
思路:将文字按照密码表转换,就变成了完整的明文和未必完整的密文的文字T,
所以明文部分就是S的前缀和T的后缀,所以可以拓展kmp
我们只需要找S[i …… len]和P的最长公共前缀
被题意恶心到了,浪费时间还收获不多。
/*
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100005;
int Next[N],extand[N];
char S[N],T[N],A[N];
char AA[N];
void GetNext(const char *T)
{
int len = strlen(T),a = 0;
Next[0] = len;
while(a < len - 1 && T[a] == T[a + 1])
a++;
Next[1] = a;
a = 1;
for(int k = 2; k < len; k ++)
{
int p = a + Next[a] - 1,L = Next[k - a];
if( (k - 1) + L >= p)
{
int j = (p - k + 1) > 0 ? (p - k + 1) : 0;
while(k + j < len && T[k + j] == T[j])
j++;
Next[k] = j;
a = k;
}
else
Next[k] = L;
}
}
void GetExtand(const char *S,const char *T)
{
GetNext(T);
int slen = strlen(S),tlen = strlen(T),a = 0;
int MinLen = slen < tlen ? slen : tlen;
while(a < MinLen && S[a] == T[a]) a++;
extand[0] = a;
a = 0;
for(int k = 1; k < slen; k ++)
{
int p = a + extand[a] - 1, L = Next[k - a];
if( (k - 1) + L >= p)
{
int j = (p - k + 1) > 0 ? (p - k + 1) : 0;
while(k + j < slen && j < tlen && S[k + j] == T[j])
j ++;
extand[k] = j;
a = k;
}
else
extand[k] = L;
}
}
int main()
{
int n;
cin >> n;
while(n--)
{
scanf("%s %s",A,S);
int lenA = strlen(A);
int lenS = strlen(S);
//求出T串
for(int i = 0;i < lenA;i++)
AA[A[i]] = 'a' + i;
for(int i = 0;i < lenS;i++)
T[i] = AA[S[i]];
GetExtand(S,T);
int i;
for(i = 0;i < lenS;i++)//找出密文长度
if(i + extand[i] >= lenS && i >= extand[i])
break;
for(int j = 0;j < i;j++)
printf("%c",S[j]);
for(int j = 0;j < i;j++)
printf("%c",AA[S[j]]);
printf("\n");
}
return 0;
}
+HDU4333
扩展KMP模板
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 500005;
char s[N],t[N];
int Next[N],extend[N];
void GetNext(char *t)
{
int len = strlen(t);
int a = 0;
Next[0] = len;
while(a < len - 1 && t[a] == t[a+1])
a++;
Next[1] = a;
a = 1;
for(int k = 2;k < len;k++)
{
int p = a + Next[a] - 1,L = Next[k-a];
if((k-1)+L >= p)
{
int j = (p-k+1) > 0?p-k+1:0;
while(k + j < len && t[k+j] == t[j])
j++;
Next[k] = j;
a = k;
}
else
Next[k] = L;
}
}
void GetExtend(char *s,char *t)
{
int a = 0;
GetNext(t);
int len1 = strlen(s);
int len2 = strlen(t);
int minlen = min(len1,len2);
while(a < minlen && s[a] == t[a])
a++;
extend[0] = a;
a = 0;
for(int k = 1;k < len1;k++)
{
int p = a+extend[a]-1,L = Next[k-a];
if((k-1)+L >= p)
{
int j = (p-k+1) >0 ?p-k+1:0;
while(k+j < len1 && j<len2 &&s[k+j] == t[j])
j++;
extend[k] = j;
a = k;
}
else
extend[k] = L;
}
}
void Getfail(char *t)
{
int len = strlen(t);
int i = 0, j = -1;
Next[0] = -1;
while(i < len)
{
if(j == -1 || t[i] == t[j])
Next[++i] = ++j;
else
j = Next[j];
}
}
int main()
{
int tt;
cin >> tt;
for(int ca = 1;ca <= tt;ca++)
{
scanf("%s",t);
strcpy(s,t);
strcat(s,t);
int len1 = strlen(s),len2 = strlen(t);
GetExtend(s,t);
Getfail(t);
int l = len2 - Next[len2];//求最小循环节
//如果串是循环的,那么每种结果都重复了多次
int rep = 1;
if(len2 % l == 0)
rep = len2 / l;
int ss = 0,su = 0,sum = 0;
for(int i = 0;i < len2;i++)
{
if(extend[i] >= len2)//最长公共前缀>=len2的话,肯定相等
su++;
else if(s[i+extend[i]] < t[extend[i]])//不相等,则要看下一位的大小
ss++;
else
sum++;
}
printf("Case %d: %d %d %d\n",ca,ss/rep,su/rep,sum/rep);
}
return 0;
}