hdu4552怪盗基德的挑战书&hdu3336Count the string【后缀数组求各前缀重复次数和】

来源:互联网 发布:js 封装自定义组件 编辑:程序博客网 时间:2024/06/05 14:17

Problem Description
It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: "abab"
The prefixes are: "a", "ab", "aba", "abab"
For each prefix, we can count the times it matches in s. So we can see that prefix "a" matches twice, "ab" matches twice too, "aba" matches once, and "abab" matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For "abab", it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.
 

Input
The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.
 

Output
For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.
 

Sample Input
14abab
 

Sample Output
6


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
aaaabab
 

Sample Output
66
 
柯密哭晕在厕所 %>_<% 这也太牵强了吧

对于height[]数组的运用有点像

spojDistinct Substrings【后缀数组 不重复子串】

对于这个题来说,先考虑极端的情况:若没有重复的前缀,那么答案是n;当有了重复的,则是原串与某个前缀存在LCP,这段重复的字符串为整体重复的次数做出的贡献是LCP,LCP

的求法是取当前区间的最小值,当前区间的范围下标是排名。故,我们往大以及往小枚举求出从rank[0]开始的height【】,当前的height最小值即为排名为i的后缀串与原串的LCP。


/**************hdu45522016.2.2278MS4528K2470 BC++**************/#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <map>#include <queue>#include <set>#include <vector>#include <string>#include <math.h>using namespace std;const int MAXN=100010;int sa[MAXN];//SA数组,表示将S的n个后缀从小到大排序后把排好序的             //的后缀的开头位置顺次放入SA中int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值int rnk[MAXN],height[MAXN];//待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,//除s[n-1]外的所有s[i]都大于0,r[n-1]=0//函数结束以后结果放在sa数组中void build_sa(int s[],int n,int m){    int i,j,p,*x=t1,*y=t2;    //第一轮基数排序,如果s的最大值很大,可改为快速排序    for(i=0;i<m;i++)c[i]=0;    for(i=0;i<n;i++)c[x[i]=s[i]]++;    for(i=1;i<m;i++)c[i]+=c[i-1];    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;    for(j=1;j<=n;j<<=1)    {        p=0;        //直接利用sa数组排序第二关键字        for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;        //这样数组y保存的就是按照第二关键字排序的结果        //基数排序第一关键字        for(i=0;i<m;i++)c[i]=0;        for(i=0;i<n;i++)c[x[y[i]]]++;        for(i=1;i<m;i++)c[i]+=c[i-1];        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];        //根据sa和x数组计算新的x数组        swap(x,y);        p=1;x[sa[0]]=0;        for(i=1;i<n;i++)            x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;        if(p>=n)break;        m=p;//下次基数排序的最大值    }}void getHeight(int s[],int n){    int i,j,k=0;    for(i=0;i<=n;i++)rnk[sa[i]]=i;    for(i=0;i<n;i++)    {        if(k)k--;        j=sa[rnk[i]-1];        while(s[i+k]==s[j+k])k++;        height[rnk[i]]=k;    }}char str[MAXN];int s[MAXN];int main(){   // freopen("cin.txt","r",stdin);//    freopen("out.txt","w",stdout);    while(scanf("%s",str)==1)    {       int len=strlen(str);       int n=len;       for(int i=0;i<n;i++) s[i]=str[i];       s[n]=0;       build_sa(s,n+1,128);       getHeight(s,n);       int tmp=rnk[0],ans=len,mm=n;       for(int i=tmp+1;i<=n;i++)       {           if(mm>height[i]) mm=height[i];           ans+=mm;       }       mm=n;       for(int i=tmp;i>1;i--)       {           if(mm>height[i]) mm=height[i];           ans+=mm;       }       printf("%d\n",ans%256);    }    return 0;}






0 0