bzoj2176 Strange string 最小表示法

本文介绍了一种求解字符串最小表示法的高效算法。通过寻找特定位置i,将原字符串断开并重新连接得到最小字典序的循环同构串。文章提供了详细的算法思路及C++实现代码。

题意:给出一个字符串s(n<=10000000),求他的最小表示法
一开始发现SA或者SAM可以做好像,然而n<=1000w,word哥还是搞最小表示法把。。
最小表示法其实就是一个字符串的最小字典序循环同构的串。
可能你还是很懵比,好举个例子。
设S=bcda,那么S的循环同构串就是cdab,dabc,abdc,他的最小表示法就是abdc.
其实就是要找的一个i的位置,从这个i开始把S断掉,然后输出的就是abdc。

怎么找这个i呢?
我们可以先来想想暴力打法(dalao请跳过)
一开始暴力肯定就是双指针嘛,设i=0,j=1,
然后就有:
i=0,j=1;
while (i

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 10000005
using namespace std;

int n;
unsigned char s[N*2];

int main()
{
    freopen("2176.in","r",stdin);//freopen("test.out","w",stdout);
    scanf("%d",&n);
    scanf("%s",s+1);
    for (int i=n+1;i<=n*2;i++)
        s[i]=s[i-n];
    int i=1,j=2;
    while (i<n&&j<n)
    {
        int k=0;
        while (s[i+k]==s[j+k]&&k<n) k++;
        if (k==n) break;
        if (s[i+k]<s[j+k]) j=max(j+k+1,i+1);
        else i=max(i+k+1,j+1);
    }
    i=min(i,j);
    for (int k=1;k<=n;k++)
        putchar(s[k+i-1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值