HDOJ 4300 Clairewd’s message

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;
}

猜你喜欢

转载自www.cnblogs.com/Sin-demon/p/10257023.html