HDU 6405 Make ZYB Happy

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/81747326

题意:给出n(n<=10000)个字符串S[1~n],每个S[i]有权值val[i],随机等概率造一个由小写字母构成的字符串T,Sum = 所有含有子串T的S[i]的val[i]之积,求Sum的期望值。
广义后缀自动机模板题。
广义后缀自动机
这个题比较特殊的地方在于,它不能打了标记后整个自动机同时沿fail链上传标记,必须边打标记边上传,因为出现多次答案只算一次。那么就有人提出了疑问,对于每个串都要单独上传标记,最坏可能每次都遍历整个自动机,不会T吗。
并不会T,因为长度为k的字符串按后缀链接遍历到的点不超过k^2个,又最多只会把整个自动机遍历一遍,所以串S的时间耗费为min(k^2,n),所以平均每个字符的时间耗费为min(k^2,n) / k <= sqrt(n)
所以总的复杂度为O(n * sqrt(n))…….
cin(+ios::sync_with_stdio(false))真好用。
AC Code:

#include<bits/stdc++.h>
#define maxn 600005
#define mod 1000000007
#define Maxc 26
using namespace std;

string s[10005];
int n , ans[maxn];

inline int cut(int a){ return a >= mod ? a - mod : a; }

inline int ksm(int base,int k)
{
    int ret=1;
    for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
    return ret;
}
int Pow[maxn];

namespace SAM
{
    int ch[maxn][Maxc]={} , h[maxn]={} , fail[maxn]={} , Len[maxn]={} , cnt , last , cur;
    int vis[maxn]={};

    void Setup()
    {
        fail[0] = -1;
        cnt = last = cur = 0;
    }

    void Insert(int val)
    {
        Len[cur = ++cnt] = Len[last] + 1 , h[cnt] = 1;
        int p = last;
        for(;p!=-1 && !ch[p][val];p=fail[p]) ch[p][val] = cur;
        if(p==-1) fail[cur] = 0;
        else
        {
            int q = ch[p][val];
            if(Len[q] == Len[p]+1) fail[cur] = q;
            else
            {
                int rec = ++cnt;
                memcpy(ch[rec] , ch[q] , sizeof ch[q]);
                fail[rec] = fail[q] , Len[rec] = Len[p]+1;
                for(;p!=-1 && ch[p][val] == q;p=fail[p]) ch[p][val] = rec;
                h[fail[cur] = fail[q] = rec] = 1;
            }
        }
        last = cur;
    }

    void Insert(string s)
    {
        int len = s.size();
        last = 0;
        for(int i=0;i<len;i++)
            Insert(s[i]-'a');
    }

    void Update(string s,int val,int tag)
    {
        int len = s.size() , r = 0;
        for(int i=0;i<len;i++)
        {
            r = ch[r][s[i]-'a'];
            for(int tmp = r;tmp!=-1 && vis[tmp] < tag;tmp = fail[tmp])
            {
                h[tmp] = 1ll * h[tmp] * val % mod;
                vis[tmp] = tag;
            }
        }
    }

    void dfs(int now)
    {
        vis[now] = maxn;
        if(now)
        {
            ans[Len[fail[now]]+1] = cut(ans[Len[fail[now]]+1] + h[now]);
            ans[Len[now]+1] = cut(ans[Len[now]+1] - h[now] + mod);
        }
        for(int i=0;i<Maxc;i++)
            if(maxn > vis[ch[now][i]])
                dfs(ch[now][i]);
    }

    void Solve()
    {
        dfs(0);
        for(int i=1;i<maxn;i++) ans[i] = cut(ans[i] + ans[i-1]);
        for(int i=1;i<maxn;i++) ans[i] = cut(ans[i] + ans[i-1]);
    }
};
using namespace SAM;

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;

    Pow[1] = 26;
    for(int i=2;i<maxn;i++) Pow[i] = 1ll * Pow[i-1] * Pow[1] % mod;
    for(int i=2;i<maxn;i++) Pow[i] = cut(Pow[i] + Pow[i-1]);

    fail[0] = -1;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        Insert(s[i]);
    }

    for(int i=1,val;i<=n;i++)
    {
        cin>>val;
        Update(s[i],val,i);
    }

    Solve();

    int q,tmp;
    cin>>q;
    for(;q--;)
    {
        cin>>tmp;
        cout<<1ll * ans[tmp] * ksm(Pow[tmp],mod-2) % mod<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/81747326