HDU4300 Clairewd’s message(exKMP)

题目链接在这里插入图片描述
在这里插入图片描述

题目大意:
给出一串S,代表加密字符,表示第i个字符会加密为S[i]
再给出一段密文,明文相连接的字符串,密文是完整的,明文不一定完整,要我们填补明文,使得密文+明文相连的字符串长度尽可能小。

解题思路:
不妨先把给出的密文+明文的字符串加密操作,那么后缀的一段肯定是明文(或者0),与原本的串匹配,公共前后缀长度不超过 len/2的情况下,能匹配的越长,就能越少地填充回去。exkmp处理即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
/*
* 扩展KMP算法
*/
//nxt[i]:x[i...m-1]与x[0...m-1]的最长公共前缀
//extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀
int nxt[100050];
int extend[100050];
char key[100050], t[100050],s[100050];
void pre_EKMP(char x[],int m,int nxt[])
{
	nxt[0]=m;
	int j=0;
	while(j+1<m && x[j]==x[j+1]) j++;
	nxt[1]=j;
	int k=1;
	for(int i=2;i<m;i++)
	{
		int p=nxt[k]+k-1;
		int L=nxt[i-k];
		if(i+L<p+1)nxt[i]=L;
		else
		{
			j=max(0,p-i+1);
			while(i+j<m && x[i+j]==x[j])j++;
			nxt[i]=j;
			k=i;
		}
	}
}
void EKMP(char x[],int m,char y[],int n,int nxt[],int extend[])
{
	pre_EKMP(x,m,nxt);
	int j=0;
	while(j<n && j<m && x[j]==y[j]) j++;
	extend[0]=j;
	int k=0;
	for(int i=1;i<n;i++)
	{
		int p=extend[k]+k-1;
		int L=nxt[i-k];
		if(i+L<p+1)
			extend[i]=L;
		else
		{
			j=max(0,p-i+1);
			while(i+j<n && j<m && y[i+j]==x[j]) j++;
			extend[i]=j;
			k=i;
		}
	}
}
char rnm[30];
int main()
{   int tt;
    cin>>tt;
    while(tt--){
    cin >> key >> t;  // 密码串
   int plen=strlen(key);
    	int tlen = strlen(t);
        int slen=tlen;
        memset(rnm,'\0',sizeof(rnm));
        for(int i=0;i<26;i++){
          rnm[key[i]-'a']=i+'a';
        }
        for(int i=0;i<tlen;i++){
           s[i]=key[t[i]-'a'];  //  解密
        }
        EKMP(t,tlen,s,slen,nxt,extend);
        int ans =tlen;
        for(int i=0; i <tlen; i++)
        {
            if(extend[i]+i>=tlen&&i>=extend[i])
            {
                ans=i;
                break;
            }
        }
           for(int i=0;i<ans;i++){

        printf("%c",t[i]);
        }
        printf("%c",rnm[t[i]-'a']);
        }
        printf("\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值