vijos1382寻找主人

题目大意:

给出两个串(长度<=1e6),问是否同构,如果同构输出最小表示。

题解:

这是最小表示法模板题。在这里好好讲一下最小表示法。

首先有一个最暴力的方法:
把所有表示搞出来排序。

时间复杂度O(n^2logn);

然后可以发现,比较两个字符串时都是从第一位向后比。

伪代码:

char s[N<<1];
int mex()
{
    scanf("%s",s+1);
    int len = strlen(s+1);
    for(int i=1;i<=len;i++)
        s[i+len]=s[i];
    int i=1,j=2,k=0;
    while(i<=len&&j<=len&&k<len)
    {
        int t = s[i+k]-s[j+k];
        if(!t)k++;
        else
        {
            if(t>0)i++;
            else j++;
            k=0;
            if(i==j)i++;
        }
    }
    return i<j?i:j;
}

时间复杂度O(n^2);

看起来可以再优化一下。

比如当前串是

扫描二维码关注公众号,回复: 4244235 查看本文章

S1S2S3S4S5S6S7S8

指针i,j分别走到S1和S5。

k=2。

这时S1S2和S5S6相同。

然后比较S3和S7。假设S3>S7,那么i直接跳过S3到达S4。

因为如果要作开头的话,S1不如S5,S2不如S6,S3不如S7;

公共原因:S3<S7。

因此模板:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000050
char a[2][2*N];
int len;
int mex(int t)
{
    int i=1,j=2,k=0;
    while(i<=len&&j<=len&&k<len)
    {
        int tmp = a[t][i+k]-a[t][j+k];
        if(!tmp)k++;
        else
        {
            if(tmp>0)i+=k+1;
            else j+=k+1;
            if(i==j)j++;
            k=0;
        }
    }
    return i<j?i:j;
}
int main()
{
    scanf("%s%s",a[0]+1,a[1]+1);
    len = strlen(a[0]+1);
    for(int i=1;i<=len;i++)a[0][len+i]=a[0][i],a[1][len+i]=a[1][i];
    int l1 = mex(0),l2 = mex(1);
    for(int i=0;i<len;i++)
        if(a[0][l1+i]!=a[1][l2+i])
        {
            printf("No\n");
            return 0;
        }
    printf("Yes\n");
    for(int i=0;i<len;i++)
        printf("%c",a[0][l1+i]);
    printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/10021783.html
今日推荐