1. 程式人生 > >HDU-4300-Clairewd’s message(KMP+特判)

HDU-4300-Clairewd’s message(KMP+特判)

博主連結

題目

在這裡插入圖片描述

題意:

先給你一個密碼錶。然後給你一個不一定完整的串。原串滿足前一半是密碼,後一半是明碼。要求你最小的補全這個串。

題解:

設給的串長度為len,則1…(len+1)/2的字母一定是密碼。我們將1…(len+1)/2的字母全部安裝密碼錶轉換成原文,然後將得到的串求Next陣列。再根據Next陣列求出最大的相等的前後綴(長度一定小於或等於len/2,題目要求),然後輸出就可以。然後這裡一定要先加一個特判是不是不存在相等的前後綴,也就是s[1]!=s[len],這時輸出原串一次,再輸出一次原串全解密的串.

程式碼:

#include<stdio.h>
#include<bits/stdc++.h>
#define met(a) memset(a,0,sizeof(a))
#define fup(i,a,n,b) for(int i=a;i<n;i+=b)
#define fow(j,a,n,b) for(int j=a;j>0;j-=b)
#define MOD(x) (x)%mod
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
char s[maxn],s1[maxn];
char t[maxn];
char m[33];
int nex[maxn];
void Get_nex() {
	int j = 0;
	for (int i = 1; s[i]; i++) {
		while (s[i] != s[j + 1] && j != 0)j = nex[j];
		if (s[i] == s[j + 1] && i != 1)j++;
		nex[i] = j;
	}
}
int main() {
	int t,n;
	scanf("%d", &t);
	while (t--) {
		scanf("%s", m+1);
		scanf("%s", s+1);
		int len = strlen(s+1);
		for (int i = 1;i<=len+1; i++)s1[i] = s[i];
		for (int j = 1; j <= (len +1)/ 2; j++) {   //進行原串前半部分解密
			for (int i = 1; i <= 26; i++) {
				if (s[j] == m[i]) {
					s[j] = 'a' + i-1;
					break;
				}
			}
		}
		Get_nex();
		int nn =0;
		int a = nex[len];
		if (a == 0) {	//	如果不存在相等的前後綴
			printf("%s", s1 + 1);
			for (int j = (len+1)/2+1; j <= len; j++) {
				for (int i = 1; i <= 26; i++) {
					if (s[j] == m[i]) {
						s[j] = 'a' + i - 1;
						break;
					}
				}
			}
			printf("%s\n", s+1);
			continue;
		}
		while (a != 0) {	//找出最大的相等的前後綴且長度小於或等於len/2
			if (s[a] == s[len]) {
				if (a <= len / 2)nn = max(nn, a);
				a = nex[a];
			}
		}
		printf("%s", s1+1);
		for (int i = nn+1; i <= len -nn; ++i)printf("%c",s[i]);
		printf("\n");
	}
}