USACO 5.5 Hidden Password

本文介绍了一种高效算法,用于解决ACM竞赛中隐藏密码问题。通过避免不必要的排序操作,利用字符串Hash和二分查找技术,实现了O(L log L)的时间复杂度,快速找到给定字符串所有循环移位后的字典序最小值起始位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

————————————————————————————————————————————————————————题解
它只让你输出最小值你为什么要排序sjq你是sb吗!!!!
这道题一开始的思路是建l个string排个序……【为什么要排序!!!】然后爆空间了
然后开始用lcp(最小公共前缀)然后排个序【为什么要排序!!!】然后超时了
我想,不能超时啊……nlognlogn啊……【为什么要排序!!!】
我又一想,哎,我为什么要排序啊?【对啊!!!!】
然后我做完了
好了这道题的思路就是把字符串复制一下,使它变成2*l长,这样我们断环为链,再处理成一个字符串hash
对于每两个开头a,b二分得出他们的lcp,然后比较lcp的下一位,或者他们完全相等比较a,b大小
这道题我们只输出最小值O(L)就可以选出最小值,加上二分的复杂度,最大也就是O(LlogL) 【所以你为什么要排序!!!】
 1 /*
 2 ID: ivorysi
 3 LANG: C++
 4 PROG: hidden
 5 */
 6 #include <iostream>
 7 #include <cstdio>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <set>
12 #include <vector>
13 #include <string.h>
14 #include <cmath>
15 #include <stack>
16 #include <map>
17 #define siji(i,x,y) for(int i=(x);i<=(y);++i)
18 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
19 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
20 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
21 #define inf 0x5f5f5f5f
22 #define ivorysi
23 #define mo 97797977
24 #define hash 974711
25 #define base 47
26 #define pss pair<string,string>
27 #define MAXN 5000
28 #define fi first
29 #define se second
30 #define pii pair<int,int>
31 #define esp 1e-8
32 typedef long long ll;
33 using namespace std;
34 char str[200005],t[200005];
35 int l,e[200005],ha[200005],x,cnt,c;
36 bool check(int a,int b,int len) {
37     return ((ll)e[2*l-a-len]*(ha[a+len-1]-ha[a-1])%mo - (ll)e[2*l-b-len]*(ha[b+len-1]-ha[b-1])%mo)%mo==0;
38 }
39 int binary(int a,int b) {
40     int le=0,ri=l,mid;
41     while(le<ri) {
42         mid=(le+ri+1)>>1;//因为最后返回的是le
43         if(check(a,b,mid)) le=mid;
44         else ri=mid-1;
45     }
46     return le;
47 }
48 bool cmp(const int &a,const int &b) {
49     x=binary(a,b);
50     return x==l ? a<b : str[a+x]<str[b+x];
51 } 
52 void solve() {
53     scanf("%d",&l);
54     siji(i,1,(l-1)/72+1) {
55         scanf("%s",str+1+(i-1)*72);
56     }
57     strcpy(t+1,str+1);
58     strcat(str+1,t+1);
59     e[0]=1;
60     siji(i,1,2*l) {
61         e[i]=(ll)e[i-1]*base%mo;
62     }
63     siji(i,1,2*l) {
64         ha[i]=(ll)(ha[i-1]+(ll)e[i]*(str[i]-'a'+1)%mo)%mo;
65     }
66     c=1;
67     siji(i,2,l) {
68         if(cmp(i,c)) c=i;
69     }
70     printf("%d\n",c-1);
71 }
72 int main(int argc, char const *argv[])
73 {
74 #ifdef ivorysi
75     freopen("hidden.in","r",stdin);
76     freopen("hidden.out","w",stdout);
77 #else
78     freopen("f1.in","r",stdin);
79 #endif
80     solve();
81     return 0;
82 }

 

 

转载于:https://www.cnblogs.com/ivorysi/p/6426424.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值