Clairewd’s message HDU - 4300(扩展kmp)

题意

给你一个密文转化为明文的规则:

qwertyuiopasdfghjklzxcvbnm

a对应q,b对应w,,,,

现在我们知道一个字符串A这个字符串是由一个密文+一个明文组成的,并且可能不完整,问你这个字符串的最短长度是多少

思路

既然是由密文与明文组成的,那么至少 i>=len(A)/2长度开始判断,对于当前位置的i来说,<i的部位是密文,>=i的部分为明文,

如果<i的部分通过转换规则转化为>=i的部分,那么这里就是分界点,所以我们就要判断>=i的部分是不是与<i的部分相等,!!!这不就是后缀与前缀的匹配嘛,或者为从i开始的与从0开始的最大前缀长度,正是扩展KMP,所以我们将A字符串全部当作为密文通过转化为明文B,以A为模板串,B为匹配串,进行扩展KMP

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
#define MAXNUM 1000050
char s1[2*MAXNUM], s2[2*MAXNUM];//s2为待匹配字符串
int s1size, s2size;
//num[i]保存s2长度为i的前缀子串在s1中出现的数目,非必需
int num[2*MAXNUM];
//extend为s1串中对应位置开始匹配的最大前缀长度
//snext为s2串中[i,len]与s2的最长公共前缀长度
int snext[2*MAXNUM],extend[2*MAXNUM];
void getextnext() 
{
	int i, length = s2size;
	snext[0] = length;
	for (i = 0; i<length - 1 && s2[i] == s2[i + 1]; i++);
	snext[1] = i;
	int a = 1;
	for (int k = 2; k < length; k++) 
	{
		int p = a + snext[a] - 1, L = snext[k - a];
		if ((k - 1) + L >= p) 
		{
			int j = (p - k + 1)>0 ? (p - k + 1) : 0;
			while (k + j<length && s2[k + j] == s2[j]) j++;// 枚举(p+1,length) 与(p-k+1,length) 区间比较 
			snext[k] = j, a = k;
		}
		else snext[k] = L;
	}
}

void kmpextend() 
{
	s1size = strlen(s1), s2size = strlen(s2);
	getextnext();
	int a = 0;
	int MinLen = s1size>s2size ? s2size : s1size;
	while (a<MinLen && s1[a] == s2[a]) a++;
	extend[0] = a, a = 0;
	for (int i = 1; i < s1size; i++) 
	{
		int p = a + extend[a] - 1, L = snext[i - a];
		if ((i - 1) + L >= p) 
		{
			int j = (p -i + 1)>0 ? (p - i + 1) : 0;
			while (i + j<s1size && j<s2size && s1[i + j] == s2[j]) 
				j++;
			extend[i] = j;
			a = i;
		}
		else extend[i] = L;
	}
    //计算Num,可去
	for (int i = 0; i < s1size; i++)
		num[extend[i]]++;
	for (int i = s2size - 1; i >= 1; i--)
		num[i] += num[i + 1];
}

int XHJ(char str[])
{
	// 已经求出next数组
	int kk;  // kk保存最短循环节
	int len=strlen(str);
	for(int i=1; i<=len; ++i)
	{
    	if(i+snext[i]>=len){
        	kk = len%i ? len : i;
        	break;
    	}
	}
	return kk;
}


map<char,char> mp;
char str1[MAXNUM];
int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		mp.clear();
		scanf("%s%s",str1,s1);
		int len1=strlen(str1);
		for(int i=0;i<len1;i++)
			mp[str1[i]]=i+'a';
		int len2=strlen(s1);
		for(int i=0;i<len2;i++) s2[i]=mp[s1[i]];
		kmpextend();
		int ans=len2;
		for(int i=len2/2;i<len2;i++)
		{
			if(extend[i]+i>=len2&&(2*i)>=len2)
			{
				ans=i;break;
			}
		}
		for(int i=0;i<ans;i++) printf("%c",s1[i]);
		for(int i=0;i<ans;i++) printf("%c",mp[s1[i]]);
		cout<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值