bzoj1398: Vijos1382寻找主人 Necklace

链接

点击跳转

字符串的最小表示法

这个算法要做的事请就是把一个字符串首尾相接形成一个环,然后找一个位置切开,使得切开后形成的字符串字典序最小

基于的原理很简单,当我比较两个开头 i , j i,j 所形成的字符串时,如果在第 k k 个位置开始不相同,那么字典序较大的那个串所对应的指针就可以直接后移 k k ,均摊时间复杂度 O ( n ) O(n)

特殊情况:如果比较的过程中两个字符串相同了,那么这个字符串一定就是字典序最小的。因为出现这种情况时,这个串一定是由一种更短的小串 r e p e a t repeat 若干次得到的,根据算法的过程就可以推出这个时候 i i j j 都指向字典序最小的开头。

具体请看代码:

struct minimal_cyclic_expression
{
    int w[maxn<<1];
    int run(char* s, int n)
    {
        int i=1, j=2, k;
        rep(k,n)w[k]=w[n+k]=s[k];
        while(i<=n and j<=n)
        {
            for(k=0;k<n and w[i+k]==w[j+k];k++);
            if(k==n)return i;
            if(w[i+k]<w[j+k])j = j+k+1==i ? i+1 : j+k+1;
            else i = i+k+1==j ? j+1 : i+k+1;
        }
        return min(i,j);
    }
}mce;

题解

求出两个串的最小循环表示然后比较一下就结束了

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1000010
#define maxe 1000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
struct minimal_cyclic_expression
{
    int w[maxn<<1];
    int run(char* s, int n)
    {
        int i=1, j=2, k;
        rep(k,n)w[k]=w[n+k]=s[k];
        while(i<=n and j<=n)
        {
            for(k=0;k<n and w[i+k]==w[j+k];k++);
            if(k==n)return i;
            if(w[i+k]<w[j+k])j = j+k+1==i ? i+1 : j+k+1;
            else i = i+k+1==j ? j+1 : i+k+1;
        }
        return min(i,j);
    }
}mce;
int n, m;
char s[maxn], t[maxn];
int main()
{
    scanf("%s%s",s+1,t+1);
    n=strlen(s+1), m=strlen(t+1);
    if(n!=m){printf("No");return 0;}
    int a=mce.run(s,n), b=mce.run(t,n);
    for(int i=0;i<n;i++)
    {
        char c1=s[a+i>n?a+i-n:a+i], c2=t[b+i>n?b+i-n:b+i];
        if(c1!=c2){printf("No");return 0;}
    }
    printf("Yes\n");
    for(int i=0;i<n;i++)putchar(s[a+i>n?a+i-n:a+i]);
    return 0;
}
发布了863 篇原创文章 · 获赞 72 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/103844195
今日推荐