您的位置:首页 > 其它

usaco 5.5 Hidden Password(最小表示法求同构)

2012-09-29 09:52 363 查看

Hidden Password

ACM South Eastern Europe -- 2003

Sometimes the programmers have very strange ways of hiding their passwords. Billy "Hacker" Geits chooses a string S composed of L (5 <= L <= 100,000) lowercase letters ('a'..'z') with length L. Then he makes and
sorts all L-1 one-letter left cyclic shifts of the string. He then takes as a password one prefix of the lexicographically first of the obtained strings (including S).
For example consider the string "alabala". The sorted cyclic one-letter left shifts (including the initial string) are:

aalabal

abalaal

alaalab

alabala

balaala

laalaba

labalaa
Lexicographically, first string is 'aalabal'. The first letter of this string ('a') is the 'a' that was in position 6 in the initial string (counting the first letter in the string as position 0).
Write a program that, for given string S, finds the start position of the first letter of the sorted list of cyclic shifts of the string. If the first element appears more than once in the sorted list, then the
program should output the smallest possible initial position.

PROGRAM NAME: hidden

INPUT FORMAT

Line 1: A single integer: L
Line 2..?: All L characters of the the string S, broken across lines such that each line has 72 characters except the last one, which might have fewer.

SAMPLE INPUT (file hidden.in)

7
alabala

OUTPUT FORMAT

Line 1: A single integer that is the start position of the first letter, as described above.

SAMPLE OUTPUT (file hidden.out)

6

题意:给你一个可循环的串,要你求出字典序最小的串,如果相同求开头最小的。。。。
分析:这题我想到死也只能想到O(n^2)的算法,不过这个算法跟最终的O(n)算法很相近,主要是我没用到最小表示的一些性质,也就是证明的问题,具体看03年,周源的论文吧,貌似论文什么的我都看不大懂啊,比较术语太多,我这种野路子T_T

代码:

/*
ID: 15114582
PROG: hidden
LANG: C++
*/
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int mm=222222;
char a[mm],c;
int i,j,k,n;
int main()
{
    freopen("hidden.in","r",stdin);
    freopen("hidden.out","w",stdout);
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;++i)
        {
            while((c=getchar())<'a'||c>'z');
            a[i+n]=a[i]=c;
        }
        i=0,j=1;
        while(i<n&&j<n)
        {
            k=0;
            if(i==j)++j;
            while(k<n&&a[i+k]==a[j+k])++k;
            if(k>=n)break;
            if(a[i+k]<a[j+k])j=j+k+1;
            else i=i+k+1;
        }
        printf("%d\n",min(i,j));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: