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

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值