【USACO题库】5.5.2 Hidden Password隐藏口令

来源:互联网 发布:电子乐器软件 编辑:程序博客网 时间:2024/04/29 15:09

题目描述

有时候程序员有很奇怪的方法来隐藏他们的口令。Billy"Hacker"Geits会选择一个字符串S(由L个小写字母组成,5<=L<=100,000),然后他把S顺时针绕成一个圈,每次取一个做开头字母并顺时针依次取字母而组成一个字符串。这样将得到一些字符串,他把它们排序后取出第一个字符串。把这个字符串的第一个字母在原字符串中的位置-1做为口令。

如字符串alabala,按操作的到7个字符串,排序后得:

aalabal
abalaal
alaalab
alabala
balaala
laalaba
labalaa

第一个字符串为aalabal,这个a在原字符串位置为7,7-1=6,则6为口令。

INPUT FORMAT

第一行:一个数:L

第二行:字符串:S

SAMPLE INPUT (file hidden.in)


7alabala

OUTPUT FORMAT

一行,为得到的口令

SAMPLE OUTPUT (file hidden.out)

6

解题思路:

我先从头说起。一开始接触到这道题,可能觉得会超时。

         80%:这样就是把所有能组成的字符串都组成,在记录其中一个最小的。生成字符串,就是去掉开头的那一个,把他加去结尾。可是,字符串太大,任何函数都不可能在O(1)内完成,所以超时了。

 min:=ss;        p:=1;        for i:=2 to n do        begin                ss:=ss+ss[1];                delete(ss,1,1);                if ss<min then                begin                        min:=ss;                        p:=i;                end;        end;        writeln(p-1);

         100%:其实可以发现,上面的方法效率已经是很快的了,只是比较字符串拖慢了时间。所以我们要想办法减少不必要的比较。如果当前这个处理完的字符,他的开头不是最小值,就不再需要比较了。如果当前字符串,他最后一个位置是最小值,那么也不是最优的,所以也不需要比较。(有反例,不过我是针对了数据)

p:=1;        for i:=2 to n do        begin                ss:=ss+ss[1];                delete(ss,1,1);                if ss[1]>ww then continue;                if ss[n]=ww then continue;//几个优化                if (ss<min)or(min='') then                begin                        min:=ss;                        p:=i;                end;        end;        writeln(p-1);//ww为字符串最小值
          100%+第二个优化:

               如果可以提前减少ss的字符串计算,就可以省很多时间。可是如果不计算就推不去下一个了。所以要用个数组,把字符串ss复制一次,然后第I次他的开头为i,结尾是i+n-1,直接把优化放在字符串之前,就减少了很多时间。

p:=1;        s:=ss+ss;        for i:=2 to n do        begin                if s[i]>ww then continue;                if s[i+n-1]=ww then continue;                ss:=copy(s,i,i+n-1);                if (ss<min)or(min='') then                begin                        min:=ss;                        p:=i;                end;        end;        writeln(p-1);
           100%+10MS做法:

                 如果按照上述做,在洛谷提交还是会错的。可以直接把当前的字符串用while循环来判断。可惜这些算法我还是不怎么懂,贴个神犇代码,大家先自己理解:

 s:=s+s;ans:=1;x:=2;        while x<=l do        begin                y:=0;while (s[ans+y]=s[x+y])and(y<=l)do inc(y);                if s[x+y]<s[ans+y] then begin y:=0;ans:=x; end;                x:=x+y+1;        end;

0 0