【bzoj1398】Vijos1382寻找主人 Necklace 最小表示法

这道题只需要把原串复制一遍,然后拿另一个串去匹配就可以了。

但是作死学了下最小表示法。

http://wenku.baidu.com/link?url=disErIxplfqlFvdZy2Zy3q7FO0hYvLBqy0rFbLe93vJfNSJM5BIh4Mh3eWq0a2NPJo-09kbvFPMgyVJ07BPyNQGiw8QPCWrtPYi-RyrULDK

最小表示法是判断两个字符串是否循环同构的东西?

其实只是一种应用。

论文里写的很详细,通过一些操作得到,如果两个字符串的最小表示相同,则这两个字符串相同。

那么就是求两个字符串的最小表示。

记两个指针i,j,任意时刻它们都不能相同,记当前匹配长度为k。

如果s[i+k]=s[j+k],那么k++

如果s[i+k]>s[j+k],那么因为[i,i+k-1]与[j,j+k-1]是相同的,所以在[i,i+k-1]中不可能有最小表示,所以i+=k+1,此时k=0。

如果s[i+k]<s[j+k],那么同上。

初始时i=0,j=1就可以了。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 1000100
 
using namespace std;
 
char s[2][maxn];
int n,m;
 
int calc(char *s)
{
    int n=strlen(s);
    int i=0,j=1,k=0;
    while (i<n && j<n && k<n)
    {
        if (s[(i+k)%n]==s[(j+k)%n]) k++;
        else
        {
            if (s[(i+k)%n]>s[(j+k)%n]) i+=k+1;
            else j+=k+1;
            if (i==j) i++;
            k=0;
        }
    }
    return min(i,j);
}
 
int main()
{
    scanf("%s%s",s[0],s[1]);
    n=strlen(s[0]);
    int j=calc(s[0]),k=calc(s[1]);
    bool w=0;
    for (int i=0;i<n;i++)
      if (s[0][(j+i)%n]!=s[1][(k+i)%n]) {w=1;break;}
    if (w) printf("No\n");
    else
    {
        printf("Yes\n");
        for (int i=0;i<n;i++) printf("%c",s[0][(j+i)%n]);
        printf("\n");
    }
    return 0;
}


你可能感兴趣的:(【bzoj1398】Vijos1382寻找主人 Necklace 最小表示法)