hdu 6153 思维+扩展kmp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153

扩展kmp不理解的看下:http://www.cnblogs.com/z1141000271/p/7404717.html

大致题意:给定一个a串作为 母串,然后b作为模式串, 
f【i】 为b的后缀的长度。 
d[i] 为b这个后缀在 a串中出现的次数。。 
问你他们的 积是多少,积mod1e9+7 

题解:赛后补题目的时候,看到大佬用扩展kmp解,就去看了下扩展kmp,然后把第一个输入的字符串当t,第二个输入的字符串当s,然后卡了一天。

无奈又去看了下大佬的题解,原来是把第二个串当t串,那么怎么解决次数问题呢。我们把两个串倒置一下,用s去匹配t(倒置后)比如 s=aabaaba t=aab 倒置之后 s1=abaabaa

t1=baa。那么extend[1]=3,extend[4]=3。那问题来了,这个求出来有什么用呢?我要求的是t的后缀在s中出现的次数,那倒置之后,是不是如果长度大的出现过了,长度小的一定会出现一次。然后用一个等差公式计数就可以了。。     服气服气。终于补完这道题目了。。。 

ac代码(略丑):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define mt(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll extend[1000001];
ll Next[1000001];
ll min(ll x,ll y)
{
    if(x>y) return y;
    return x;
}
void getNext(string t)
{
    mt(Next);
    ll len=t.length();
    Next[0]=len;
    ll a,p;
    a=1;
    while( a<len && t[a]==t[a-1]) a++;
    Next[1]=a-1;
    a=1;
    for(ll i=2;i<len;i++)
    {
        p=a+Next[a]-1;
        if((i-1)+Next[i-a] < p ) Next[i]=Next[i-a];
        else
        {
            ll j = (p - i + 1) > 0 ? (p - i + 1) : 0;
            while(i + j < len && t[i+j] == t[j]) j++;
            Next[i]=j;
            a=i;
        }
    }
}
void exkmp(string s,string t) // t->next s->extend
{
    getNext(t);
    ll a,p;//
    ll slen=s.length();
    ll tlen=t.length();
    a=p=0;
    ll len=min(s.length(),t.length());
    while(p<len && t[p]==s[p]) p++; // after
    extend[0]=p;
    for(ll i=1;i<slen;i++)
    {
        p=a+extend[a]-1; // update
        if( (i-1)+Next[i-a] < p) extend[i]=Next[i-a];
        else
        {
            ll j = (p - i + 1) > 0 ? (p - i + 1) : 0;
            while( j < tlen && i+j < slen && s[i + j] == t[j]) j++;
            extend[i]=j;
            a=i;
        }
    }
}
int main()
{
    string s,t;// s->exkmp t->Next
    int Case;
    scanf("%d",&Case);
    while(Case--)
    {
        cin>>s>>t;
        reverse(s.begin(),s.end());
        reverse(t.begin(),t.end());
        exkmp(s,t);
        ll ans=0;
        int len=s.size();
        for(int i=0;i<len;i++)
        {
            ans=(ans+extend[i]*(extend[i]+1LL)/(2LL))%mod;
        }
        cout<<ans<<endl;
    }
    return 0;
}

这个包含的关系要理清楚——匹配长度较大的成立,长度小的也成立。

posted @ 2017-08-21 15:45  猪突猛进!!!  阅读(144)  评论(0编辑  收藏  举报