木子亚日乀  

题意:求一个字符串的所有后缀在母串中的出现次数*后缀的长度的总和。

题目链接:http://acm.split.hdu.edu.cn/viewcode.php?rid=22147273

思路:先预处理sum[1...n]的值及sum[i]=1+..+i,然后将两个字符串反转,然后用扩展KMP求出翻转后的母串的EX数组。然后对任一个位置的他对答案的贡献就是sum[EX[i]];

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000005
typedef long long ll;
const int MOD=1e9+7;
ll num[maxn];
char s[maxn];
char t[maxn];
int Next[maxn];
int ex[maxn];
void init()
{
    num[0]=0;
    for(int i=1;i<=maxn;i++)
    num[i]=(num[i-1]+i)%MOD;
}
void GETNEXT(char *str)
{
    int i=0,j,po,len=strlen(str);
    Next[0]=len;
    while(str[i]==str[i+1]&&i+1<len)
    i++;
    Next[1]=i;
    po=1;
    for(i=2;i<len;i++)
    {
        if(Next[i-po]+i<Next[po]+po)
        Next[i]=Next[i-po];
        else
        {
            j=Next[po]+po-i;
            if(j<0)j=0;
            while(i+j<len&&str[j]==str[j+i])
            j++;
            Next[i]=j;
            po=i;
        }
    }
}
ll EXKMP(char *s1,char *s2)
{
    int i=0,j,po,len=strlen(s1),l2=strlen(s2);
    GETNEXT(s2);
    ll sum=0;
    while(s1[i]==s2[i]&&i<l2&&i<len)
    i++;
    ex[0]=i;
    po=0;
    sum=(sum+num[ex[0]])%MOD;
    for(i=1;i<len;i++)
    {
        if(Next[i-po]+i<ex[po]+po)
        ex[i]=Next[i-po];
        else
        {
            j=ex[po]+po-i;
            if(j<0)j=0;
            while(i+j<len&&j<l2&&s1[j+i]==s2[j])
            j++;
            ex[i]=j;
            po=i;
        }
        sum=(sum+num[ex[i]])%MOD;
    }
    return sum;
}
int main()
{
    init();
    int k;
    scanf("%d",&k);
    while(k--)
    {
        scanf("%s%s",s,t);
        strrev(s);
        strrev(t);
        printf("%lld\n",EXKMP(s,t));
    }
    return 0;
}

 

posted on 2017-10-10 16:59  木子亚日乀  阅读(164)  评论(0)    收藏  举报