【HDU4552】 怪盗基德的挑战书(后缀数组)

怪盗基德的挑战书

Problem Description
  “在树最美丽的那天,当时间老人再次把大钟平均分开时,我会降临在灯火之城的金字塔前,带走那最珍贵的笑容。”这是怪盗基德盗取巴黎卢浮宫的《蒙娜丽莎的微笑》这幅画时,挑战书上的内容。
  但这次,怪盗基德的挑战书上出现了一串串小写字母“aaab sdfeeddd...”。柯南以小学生的眼睛,超凡高中生的头脑,快速统计各种字母频率,字符串长度,并结合挑战书出现的时间等信息,试图分析怪盗基德的意图。最后,他将线索锁定在字符串的循环次数上。并且进一步推理发现,从字符串的第一位开始,到第i位,形成该字符串的子串(c1, c2, c3 ... ci )。对于某一子串ci在该字符串中出现的次数记为ki,则全部子串的循环次数总和AIM = k1 + k2 + ... + ki + ... + kn,柯南发现,AIM恰好对应一个ASCII码!所以,只要把挑战书上的字符串转变成数字,再找到对应的ASCII码,就可以破解这份挑战书了!
  现在,你的任务就是把字符串转变成对应数字,因为ASCII码以及扩展ASCII码全部只有256个,所以,本题只要把结果对256取余即可。
Input
输入有多组测试数据;
每组测试数据只有一个字符串,由各种小写字母组成,中间无空格。
字符串的长度为L(0 < L <= 100000)。
Output
请计算并输出字符串的AIM值,每组数据输出一行。
Sample Input
aaa
abab
 
Sample Output
6 6
 
 
【题意】
  给一个串s,求s的每个前缀出现次数之和。
 
【分析】

  用后缀数组求的话,就是求出每个后缀和最长的后缀的公共前缀长度就可以了。

  就是rank[1]的位置往两边找。

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define INF 0xfffffff
  9 #define Maxl 100010
 10 #define Mod 256
 11 
 12 int k,la;
 13 char a[Maxl],b[Maxl];
 14 int c[Maxl];
 15 int cl;
 16 
 17 int sa[Maxl],rk[Maxl],Rs[Maxl],wr[Maxl],y[Maxl];
 18 //sa -> 排名第几的是谁
 19 //rk -> i的排名
 20 //Rs数值小于等于i的有多少个
 21 //y -> 第二关键字排名第几的是谁(类似sa)
 22 int height[Maxl];
 23 
 24 int mymin(int x,int y) {return x<y?x:y;}
 25 
 26 void get_sa(int m)
 27 {
 28    memcpy(rk,c,sizeof(rk));
 29     for(int i=0;i<=m;i++) Rs[i]=0;
 30     for(int i=1;i<=cl;i++) Rs[rk[i]]++;
 31     for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
 32     for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;
 33     
 34     int ln=1,p=0;
 35     while(p<cl)
 36     {
 37        int k=0;
 38         for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;
 39         for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln;
 40         for(int i=1;i<=cl;i++) wr[i]=rk[y[i]];
 41         
 42         for(int i=0;i<=m;i++) Rs[i]=0;
 43         for(int i=1;i<=cl;i++) Rs[wr[i]]++;
 44         for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
 45         for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];
 46         
 47         for(int i=1;i<=cl;i++) wr[i]=rk[i];
 48         for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;
 49         p=1;rk[sa[1]]=1;
 50         for(int i=2;i<=cl;i++)
 51         {
 52             if(wr[sa[i]]!=wr[sa[i-1]]||wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;
 53             rk[sa[i]]=p;
 54         }
 55         m=p,ln*=2;
 56     }
 57     sa[0]=rk[0]=0;
 58 }
 59 
 60 void get_he()
 61 {
 62     int kk=0;
 63     for(int i=1;i<=cl;i++)
 64     {
 65         int j=sa[rk[i]-1];
 66         if(kk) kk--;
 67         while(c[i+kk]==c[j+kk]&&i+kk<=cl&&j+kk<=cl) kk++;
 68         height[rk[i]]=kk;
 69     }
 70 }
 71 
 72 void ffind()
 73 {
 74     int ans=0,minn=INF;
 75     ans+=cl;
 76     for(int i=rk[1];i>=2;i--)
 77     {
 78         minn=mymin(minn,height[i]);
 79         ans=(ans+minn)%Mod;
 80     }minn=INF;
 81     for(int i=rk[1]+1;i<=cl;i++)
 82     {
 83         minn=mymin(minn,height[i]);
 84         ans=(ans+minn)%Mod;
 85     }
 86     printf("%d
",ans);
 87 }
 88 
 89 int main()
 90 {
 91     while(scanf("%s",a)!=EOF)
 92     {
 93         cl=strlen(a);
 94         for(int i=0;i<cl;i++) c[i+1]=a[i]-'a'+1;
 95         get_sa(30);
 96         get_he();
 97         ffind();
 98     }
 99     return 0;
100 }
[HDU4522]

2016-07-17 15:50:30

原文地址:https://www.cnblogs.com/Konjakmoyu/p/5678679.html