Tricky and Clever Passwordcsnd

来源:互联网 发布:seo怎么自学 编辑:程序博客网 时间:2024/05/16 23:44

一开始不懂什么是KMP算法,网上搜了一下,觉得这篇写得让我最能接受

http://www.ituring.com.cn/article/59881

我从里面摘抄了一些点子:

1.KMP算法优化字符串匹配的方法:寻找最长首尾匹配位置

2.首尾匹配位置就是说,给定一个字符串N(长度为n,即N由N[0]...N[n]组成),找出是否存在这样的i,使得N[0]=N[n-i],N1=N[n-i-1],……,N[i]=N[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 2333using 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[n];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;}

0 0
原创粉丝点击