您的位置:首页 > 其它

洛谷P1709 [USACO5.5]隐藏口令Hidden Password

2017-07-17 08:26 218 查看
题目描述

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

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

aalabal

abalaal

alaalab

alabala

balaala

laalaba

labalaa

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

输入输出格式

输入格式:

第一行:一个数:N

第二行开始:字符串:S(每72个字符一个换行符)

输出格式:

一行,为得到的口令

输入输出样例

输入样例#1:

7

anabana

输出样例#1:

6

说明

题目满足:

30%的数据n<=10000

70%的数据n<=100000

100%的数据n<=5000000

时限 1s

题目翻译来自NOCOW。

USACO Training Section 5.5

//20170523新增数据四组

我们以题目中的数据为例,有如下的一个字符串:



对于这个字符串,我们定义两个指针分别为i和 j分别指向 ‘a′和 ′n′ 即i=0j=1 再定义一个累加器 k 则表示分别以 i和 j为首的字符串的第 k个字符.



根据贪心思想,每一项显然要选最小的最好。在这里 ′n′ 的字典序大于′a′ 那么j显然不会是我们所要的答案那么我们就对j进行移位即j++接下来我们便重复上面的操作



因为i和j所指的值是相同的,所以我们并不能通过比较这一位从而得出这两个字符串的顺序关系所以我们就要对k 进行移位即 k++



我们对i+k 和 j+k 所指的字符进行比较,显然可以得出′b′ 是比′n′ 要更优的那么这时候我们就要对i进行移位,因为在[i,i+k)内我们都已经判断完了,那么我们就可以将i移到 i+k+1 继续接下来的判断。根据如上的操作我们就可以写出如下的伪代码:

i = 0 ; j = 1 ; k = 0;
while(i < length && j < length){
if s[i + k] == s[j + k] k++
if s[i + k] >  s[j + k] i = i + k + 1;
if s[i + k] <  s[j + k] j = j + k + 1;
……
}


但是我们还要考虑以下几个问题

1.当i=j时,我们的操作便无法正常的运行,因为显然的在i=j时,i+k=j+k,这样的话我们的k就会不断的增加从而导致WA

2. i+k 和j+k是可能越界的

3. k是可能大于length的

解决方法如下:

1.当i=j时,j++

2.只要执行(i+k)modlength和(j+k)modlength即可

3.限制k<length ,在k=length 直接返回i和j中位置较前的即可

完整代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn=5000110;
int n;
char s[maxn];
int Mini(int l)
{
int i,j,k;
i=0;j=1;k=0;
while(i<l&&j<l)
{
k=0;
while(s[(i+k)%l]==s[(j+k)%l]&&k<l) k++;
if(k==l) return (i<j)?i:j;
if(s[(i+k)%l]>s[(j+k)%l])i=i+k+1;
else j=j+k+1;
if(i==j)j++;
}
return (i<j)?i:j;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)cin>>s[i];
int l=Mini(n);
cout<<l<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: