It's known to all that ZYB is godlike, so obviously he has a large number of titles, such as  m.

InputThe first line contains an integer 109+7.Sample Input

2
zybnb
ybyb
3 5
4
1
2
3
4

Sample Output

769230776
425925929
891125950
633120399

        
 

Hint

For the first query, you can bring him 3 happiness points if you say "z" or "n", and 15 happiness points if you say "y" or "b"; all other strings of length 1 bring no 
happiness point to ZYB. Therefore, the expectation is (2×3+2×15)/26 = 18/13, and the answer is 18×13^(-1) mod (10^9+7) = 769230776.


题意:

给你n个字符串,然后每个字符串有一个快乐值。然后给你m个询问,每个询问给你一个长度,让你写出一个不大于这个长度的字串。这个字串的权值定义为,如果这个字符串中出现过第i个给定字符串的子串,那么权值乘以第i个字符串的快乐值,最后答案就是多个快乐值相乘。现在问你给定长度的字符串权值的期望。

思路:

由于要用到多个字符串的所有子串,所以我们很容易想到广义SAM.对于一个长度m,那么它的贡献为长度1~m所有子串的贡献和,考虑它的分母就是26,262,263...26m 的和,我们可以预处理出来。考虑它的分子就是后缀自动机上面所有出现的长度小于等于m的子串的贡献和。在后缀自动机中的parent树中,如果p所代表的子串出现的话,那么fa[p]所代表的的子串一定出现,那么len[fa[p]]+1~len[p]的长度都会出现,而且贡献为len[p]的贡献,根据right数组的定义,parent的出现次数要比x多,那么长度介于最长后缀和本身长度之间的后缀的出现次数肯定与x的出现次数相同。如果不同,那么parent肯定会指向第一个不相同的后缀对应的节点。所以说这从parent的长度加一到x的长度,这一整段的贡献我们都要计算上去。我们用一个前缀和数组sum,记录对应长度的贡献。对应的,区间 [len[fa[x]]+1,len[x]] 上的贡献都是y,表现在sum上面就是两个端点一加一减。统计完毕后,对sum求一遍前缀和,之后sum[i]表示所有长度为i的串的贡献。然后再次对sum求一次前缀和,这样的话sum[i]就表示所有长度为1~i的串的贡献。

 

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
typedef long long ll;
const int maxn=1e6+10;
int pw[maxn],n,m;
int flag[maxn],h[maxn],sum[maxn],ans[maxn];
string s[maxn];
bool vis[maxn];
int qpow(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=(ll)ans*a%mod;
        a=(ll)a*a%mod; b>>=1;
    }
    return ans;
}
void Init()
{
    pw[0]=1;
    for(int i=1;i<maxn;i++)
        pw[i]=(ll)pw[i-1]*26ll%mod;
    for(int i=2;i<maxn;i++)
        pw[i]=(pw[i]+pw[i-1])%mod;
}
struct SAM{
    int fa[maxn<<1],l[maxn<<1],nxt[maxn<<1][26];
    int last,tot;
    void Init()
    {
        last=tot=1; 
        memset(nxt[tot],0,sizeof nxt[tot]);
        l[tot]=fa[tot]=0;
    }
    int NewNode()
    {
        ++tot;
        memset(nxt[tot],0,sizeof nxt[tot]);
        l[tot]=fa[tot]=0;
        return tot;
    }    
    void Insert(int ch)
    {
        int p,q,np,nq;
        if(nxt[last][ch])
        {
            p=last;q=nxt[p][ch];
            if(l[q]==l[p]+1) last=q;//////
            else
            {
                nq=NewNode();
                l[nq]=l[p]+1;fa[nq]=fa[q];
                memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
                fa[q]=nq;
                while(p&&nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p];
                last=nq;//////
            }
        }
        else
        {
            np=NewNode(),p=last;
            last=np; l[np]=l[p]+1;
            while(p&&!nxt[p][ch]) nxt[p][ch]=np,p=fa[p];
            if(!p) fa[np]=1;
            else
            {
                q=nxt[p][ch];
                if(l[q]==l[p]+1) fa[np]=q;
                else
                {
                    nq=NewNode();
                    memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
                    fa[nq]=fa[q];
                    l[nq]=l[p]+1;
                    fa[q]=fa[np]=nq;
                    while(p&&nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p];
                }
            }
        }
    }
    void cal(string s,int val,int tag)
    {
        int cur=1;
        for(int i=0;s[i];i++)
        {
            cur=nxt[cur][s[i]-'a'];
            for(int tmp=cur;tmp&&flag[tmp]!=tag;tmp=fa[tmp])
                ans[tmp]=1LL*ans[tmp]*val%mod,flag[tmp]=tag;
        }
    }
    void build(int cur)
    {
        vis[cur]=1;
        sum[l[fa[cur]]+1]=(sum[l[fa[cur]]+1]+ans[cur])%mod;
        sum[l[cur]+1]=(sum[l[cur]+1]-ans[cur]+mod)%mod;
        for(int i=0;i<26;i++)
        {
            int Nxt=nxt[cur][i];
            if(Nxt&&!vis[Nxt]) build(Nxt);
        }
    }
} sam;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    Init(); sam.Init();
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>s[i]; sam.last=1;
        for(int j=0;s[i][j];++j)
            sam.Insert(s[i][j]-'a');
    }
    fill(ans,ans+maxn,1);
    for(int i=1;i<=n;++i) cin>>h[i];
    for(int i=1;i<=n;++i) sam.cal(s[i],h[i],i);
    sam.build(1); sum[0]=0;
    for(int i=1;i<maxn;++i) sum[i]=(sum[i]+sum[i-1])%mod;
    for(int i=1;i<maxn;++i) sum[i]=(sum[i]+sum[i-1])%mod;
    cin>>m;
    while(m--)
    {
        int k; cin>>k;
        cout<<1LL*sum[k]*qpow(pw[k],mod-2)%mod<<endl;
    }
    return 0;    
} 
View Code

相关文章:

  • 2022-03-09
  • 2022-01-25
  • 2022-12-23
  • 2022-12-23
  • 2021-05-24
  • 2021-11-03
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-01-16
  • 2021-07-10
  • 2021-09-24
  • 2021-06-13
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案