usaco training 5.5.2 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

【译题】

描述

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

第一个字母所在的位置是0

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

aalabal abalaal alaalab alabala balaala laalaba labalaa

第一个字符串为aalabal,这个a在原字符串位置为6,则6为口令。 当字符串相同时,输出编号最小的(即对于aaaa输出0)

[编辑]格式

PROGRAM NAME: hidden

INPUT FORMAT:

(file hidden.in)

INPUT FORMAT 第1行:一个数:L

第2..?行:字符串:S(每行72个字符,最后一行可能不够)

OUTPUT FORMAT:

(file hidden.out) 一行,为得到的口令

[编辑]SAMPLE INPUT

7
alabala

[编辑]SAMPLE OUTPUT

6

【分析】这道题看样子要用高级数据结构吧。但是我想暴力卡过去。第一次先扫一遍,把最小的字母位置记录下来。而且连续的一串只需记第一个。然后像滚动数组一样,一点一点比较当前数组中的后一位字母,直到只有1个位置剩下。   ------>>>>>>>但是,最后一个点超时了!!!

【代码1】

/*
PROG:hidden
ID:juan1973
LANG:C++
*/
#include<stdio.h>
#include<string>
using namespace std;
char s[200005],ch,chh;
int n,i,cnt,tot,now,step,temp;
int a[2][200005];
int main()
{
  freopen("hidden.in","r",stdin);
  freopen("hidden.out","w",stdout);
  scanf("%d",&n);
  s[0]=getchar();
  s[0]='!';ch='z'+1;
  for (i=1;i<=n;i++)
  {
    chh=getchar();
    while (chh<'a'||chh>'z') 
      chh=getchar();
    s[i]=s[i+n]=chh;
    if (s[i]<ch) {ch=s[i];cnt=1;a[0][1]=i;}
    if (s[i]==ch&&s[i-1]!=s[i]) a[0][++cnt]=i;
  }
  while (cnt>1&&step<n-1)
  {
    tot=0;ch='z'+1;step++;now^=1;
    for (i=1;i<=cnt;i++)
    {
      temp=a[now^1][i];
      if (s[temp+step]<ch)
      {ch=s[temp+step];tot=1;a[now][1]=temp;}
      else if (s[temp+step]==ch) a[now][++tot]=temp;
    }
    cnt=tot;
  }
  printf("%d\n",a[now][1]-1);
  return 0;
}

【深入】于是上网找题解。据说正解是后缀数组,可惜我不会。当然各种强大的标程也飞来飞去。学习一位超级大牛,写了一份原理类似,但轻松秒过的程序。

【代码2】

/*
PROG:hidden
ID:juan1973
LANG:C++
*/
#include<stdio.h>
#include<string>
using namespace std;
char s[200005],ch;
int n,i,j,k;
int main()
{
  freopen("hidden.in","r",stdin);
  freopen("hidden.out","w",stdout);
  scanf("%d",&n);
  getchar();
  for (i=0;i<n;i++)
  {
    ch=getchar();
    if (ch>='a'&&ch<='z') s[i]=s[i+n]=ch;else i--;
  }
  i=0;j=1;
  while (j<=n)
  {
    for (k=0;k<n;k++)
      if (s[i+k]!=s[j+k]) break;
    if (s[i+k]==s[j+k]) break;
    if (s[i+k]<s[j+k]) j=j+k+1;else i=i+k+1;
    if (i==j) j++;
  }
  printf("%d\n",i);
  return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值