Tricky and Clever Passwordcsnd
2017-03-18 21:42
330 查看
一开始不懂什么是KMP算法,网上搜了一下,觉得这篇写得让我最能接受
http://www.ituring.com.cn/article/59881
我从里面摘抄了一些点子:
1.KMP算法优化字符串匹配的方法:寻找最长首尾匹配位置。
2.首尾匹配位置就是说,给定一个字符串N(长度为n,即N由N[0]...N
组成),找出是否存在这样的i,使得N[0]=N[n-i],N1=N[n-i-1],……,N[i]=N
,不存在返回-1。
3.对于给定的字符串N,如何返回其最长首尾匹配位置?如abca,返回0,表示第0位与最后一位匹配;abcab,返回1,表示N[0,1]=N[n-1,n];abc,返回-1,表示没有首尾匹配,等等。
4.很好的简化:
5.kmp程序,其逻辑与
题目:
在年轻的时候,我们故事中的英雄——国王 Copa——他的私人数据并不是完全安全地隐蔽。对他来说是,这不可接受的。因此,他发明了一种密码,好记又难以破解。后来,他才知道这种密码是一个长度为奇数的回文串。
Copa 害怕忘记密码,所以他决定把密码写在一张纸上。他发现这样保存密码不安全,于是他决定按下述方法加密密码:他选定一个整数 X ,保证 X 不小于 0 ,且 2X 严格小于串长度。然后他把密码分成 3 段,最前面的 X 个字符为一段,最后面的 X 个字符为一段,剩余的字符为一段。不妨把这三段依次称之为 prefix, suffix, middle 。显然, middle 的长度为一个大于 0 的奇数,且 prefix 、 suffix 的长度相等。他加密后的密码即为 A + prefix + B + middle
+ C + suffix ,其中 A 、 B 、 C 是三个由 Copa 选定的字符串,且都有可能为空, + 表示字符串相连。
许多年过去了。Copa 昨天找到了当年写下加密后字符串的那张纸。但是,Copa 把原密码、A、B、C 都忘了。现在,他请你找一个尽量长的密码,使得这个密码有可能被当年的 Copa 发明、加密并写下。
输入格式
输入包含一个只含有小写拉丁字母的字符串,长度在 1 到 10^5 之内。
输出格式
第一行包含一个整数 k ,表示你找到的原密码分成的 3 个部分中有多少个非空字符串。显然 k in {1, 3} 。接下来 k 行,每行 2 个用空格分开的整数 x_i l_i ,表示这一部分的起始位置和长度。要求输出的 x_i 递增。
起始位置 x_i 应该在 1 到加密后的字符串长度之间。 l_i 必须是正整数,因为你只要输出非空部分的信息。 middle 的长度必须为奇数。
如果有多组答案,任意一组即可。提示:你要最大化的是输出的 l_i 的总和,而不是 k 。
样例输入
abacaba
样例输出
1
1 7
样例输入
axbya
样例输出
3
1 1
2 1
5 1
样例输入
xabyczba
样例输出
3
2 2
4 1
7 2
数据规模和约定
对于 10% 的数据: n <= 10
对于 30% 的数据: n <= 100
对于 100% 的数据: n <= 100000
存在 20% 的数据,输出文件第一行为 1 。
具体做法参考http://blog.csdn.net/popoqqq/article/details/45696305
代码:
http://www.ituring.com.cn/article/59881
我从里面摘抄了一些点子:
1.KMP算法优化字符串匹配的方法:寻找最长首尾匹配位置。
2.首尾匹配位置就是说,给定一个字符串N(长度为n,即N由N[0]...N
组成),找出是否存在这样的i,使得N[0]=N[n-i],N1=N[n-i-1],……,N[i]=N
,不存在返回-1。
3.对于给定的字符串N,如何返回其最长首尾匹配位置?如abca,返回0,表示第0位与最后一位匹配;abcab,返回1,表示N[0,1]=N[n-1,n];abc,返回-1,表示没有首尾匹配,等等。
4.很好的简化:
5.kmp程序,其逻辑与
getnext()函数(即前面寻找最长首位匹配函数)相同,因为都是在进行字符串匹配,只不过一个是匹配自身,一个是两个对比而已。
题目:
在年轻的时候,我们故事中的英雄——国王 Copa——他的私人数据并不是完全安全地隐蔽。对他来说是,这不可接受的。因此,他发明了一种密码,好记又难以破解。后来,他才知道这种密码是一个长度为奇数的回文串。
Copa 害怕忘记密码,所以他决定把密码写在一张纸上。他发现这样保存密码不安全,于是他决定按下述方法加密密码:他选定一个整数 X ,保证 X 不小于 0 ,且 2X 严格小于串长度。然后他把密码分成 3 段,最前面的 X 个字符为一段,最后面的 X 个字符为一段,剩余的字符为一段。不妨把这三段依次称之为 prefix, suffix, middle 。显然, middle 的长度为一个大于 0 的奇数,且 prefix 、 suffix 的长度相等。他加密后的密码即为 A + prefix + B + middle
+ C + suffix ,其中 A 、 B 、 C 是三个由 Copa 选定的字符串,且都有可能为空, + 表示字符串相连。
许多年过去了。Copa 昨天找到了当年写下加密后字符串的那张纸。但是,Copa 把原密码、A、B、C 都忘了。现在,他请你找一个尽量长的密码,使得这个密码有可能被当年的 Copa 发明、加密并写下。
输入格式
输入包含一个只含有小写拉丁字母的字符串,长度在 1 到 10^5 之内。
输出格式
第一行包含一个整数 k ,表示你找到的原密码分成的 3 个部分中有多少个非空字符串。显然 k in {1, 3} 。接下来 k 行,每行 2 个用空格分开的整数 x_i l_i ,表示这一部分的起始位置和长度。要求输出的 x_i 递增。
起始位置 x_i 应该在 1 到加密后的字符串长度之间。 l_i 必须是正整数,因为你只要输出非空部分的信息。 middle 的长度必须为奇数。
如果有多组答案,任意一组即可。提示:你要最大化的是输出的 l_i 的总和,而不是 k 。
样例输入
abacaba
样例输出
1
1 7
样例输入
axbya
样例输出
3
1 1
2 1
5 1
样例输入
xabyczba
样例输出
3
2 2
4 1
7 2
数据规模和约定
对于 10% 的数据: n <= 10
对于 30% 的数据: n <= 100
对于 100% 的数据: n <= 100000
存在 20% 的数据,输出文件第一行为 1 。
具体做法参考http://blog.csdn.net/popoqqq/article/details/45696305
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 #define MOD 999911657 #define BASE 2333 using namespace std; int n,ans; char s[M],rev_s[M]; int next[M],f[M],pos[M]; pair<int,int> intervals[M]; int log_2[M],a[M][17],_ans[M]; void KMP() { int i,fix=0;//fix匹配成功的个数 for(i=2;i<=n;i++) //模式值数组的求取 { while( fix && rev_s[fix+1]!=rev_s[i] ) fix=next[fix]; if( rev_s[fix+1]==rev_s[i] ) ++fix; next[i]=fix; } fix=0;//KMP匹配——rev_s和s匹配 for(i=1;i<=n;i++) { while( fix && rev_s[fix+1]!=s[i] ) fix=next[fix]; if( rev_s[fix+1]==s[i] ) ++fix; if( i+fix>=n ) return ; if(!pos[fix]) { pos[fix]=i; intervals[fix]=make_pair(i+1,n-fix); } } } void Manacher() { int i,id=1,mx=1; s[0]='$'; for(i=1;i<=n;i++) { f[i]=min(mx-i+1,f[id+id-i]); while(s[i+f[i]]==s[i-f[i]]) ++f[i]; if(i+f[i]-1>mx) mx=i+f[i]-1,id=i; } } int Get_Max(int x,int y) { int len=log_2[y-x+1]; return max(a[x][len],a[y-(1<<len)+1][len]); } int Bisection(int x,int y) { int l=1,r=y-x+2>>1; while(l+1<r) { int mid=l+r>>1; if( Get_Max(x+mid-1,y-mid+1)>=mid ) l=mid; else r=mid; } return Get_Max(x+r-1,y-r+1)>=r?r:l; } int main() { int i,j; scanf("%s",s+1);n=strlen(s+1); for(i=1;i<=n;i++) //翻转s,存放在rev_s里面 rev_s[i]=s[n-i+1]; KMP(); Manacher(); pos[0]=1;intervals[0]=make_pair(1,n); for(i=2;i<=n;i++) log_2[i]=log_2[i>>1]+1;//i>>1——i/2 for(i=1;i<=n;i++) a[i][0]=f[i]; for(j=1;j<=log_2 ;j++) for(i=1;i+(1<<j)-1<=n;i++) a[i][j]=max(a[i][j-1],a[i+(1<<j-1)][j-1]);//左移n位,相当于乘以2^n; for(i=0;pos[i];i++) { _ans[i]=2*Bisection(intervals[i].first,intervals[i].second)-1; if(i*2+_ans[i]>ans*2+_ans[ans]) ans=i; } if(ans==0) { cout<<1<<endl; for(i=1;i<=n;i++) if(f[i]*2-1==_ans[0]) { cout<<i-f[i]+1<<' '<<_ans[0]<<endl; return 0; } } else { cout<<3<<endl; cout<<pos[ans]-ans+1<<' '<<ans<<endl; int l=intervals[ans].first,r=intervals[ans].second; for(i=l;i<=r;i++) if( min(min(i-l,r-i)+1,f[i])*2-1==_ans[ans] ) { cout<<i-(_ans[ans]>>1)<<' '<<_ans[ans]<<endl; break; } cout<<n-ans+1<<' '<<ans<<endl; } return 0; }
相关文章推荐
- 算法笔记_055-蓝桥杯练习 Tricky and Clever Password (Java)
- 算法练习——Tricky and Clever Password
- Codeforces #30E: Tricky and Clever Password 题解
- codeforces 30E 蓝桥杯 Tricky and Clever Password
- 蓝桥杯-Tricky and Clever Password(java)
- 算法训练 Tricky and Clever Password
- 算法笔记_055:蓝桥杯练习 Tricky and Clever Password (Java)
- 算法笔记_055-蓝桥杯练习 Tricky and Clever Password (Java)
- Tricky and Clever Password 【KMP+Manacher】【蓝桥杯试题】
- Codeforces Round #288 (Div. 2) D Tanya and Password
- Password authentication failed, Please verify that the username and password are correct
- C. Dasha and Password(模拟,暴力)
- Codeforces Round #288 (Div. 2) D. Tanya and Password 欧拉通路
- Disable to auto complete fill in user name and password
- Codeforces Round #394 (Div. 2) C. Dasha and Password
- Codeforces 761C-Dasha and Password
- 【枚举】Codeforces Round #394 (Div. 2) C. Dasha and Password
- Resolve and Remove "BAD PASSWORD: It is Based on a Dictionary Word "in Linux
- Authenticate a user against the Active Directory using the user ID and password
- Oracle Default Users And Password