LOJ6071. "2017 Shandong round training Day5" String [SAM]

SIZE

Thinking

This question is obviously to count every legitimate first string represented by a unique method. (I did not even think this is really hopeless)

How unique? Easy to think of the prefix as much in the first string fill out, and then fill the second, third ......

How to do this? You can build a SAM, and then use the \ (nxt \) array to determine whether it can fill in later.

So how do you count it? DP front to back if you want to record a binary string that indicates which character in \ (nxt \) inside, or directly with the record which SAM node, the complexity of the explosion.

From the back DP, so you only need to record what the top of the character Yes. I.e. set \ (dp_ {i, c} \) is represented by the back \ (I \) strings, is the foremost character \ (C \) is the number of programs.

How to transfer? This enumeration of SAM node string, it can only take back a no-show (nxt \) \ character. Note that a node represents a lot of strings, it can be transferred to many places.

Other explanations do not understand why topological sorting?

Code

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 2020202
    #define mod 1000000007ll
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char __sr[1<<21],__z[20];int __C=-1,__zz=0;
    inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
    inline void print(register int x)
    {
        if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
        while(__z[++__zz]=x%10+48,x/=10);
        while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
    }
    void file()
    {
        #ifdef NTFOrz
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n;
char s[sz];int L[sz],R[sz];
int sum[sz][26];

namespace SAM
{
    struct hh{int link,len,ch[26];}a[sz];
    int lst,cnt;
    void init(){lst=cnt=1;rep(i,0,25) a[1].ch[i]=0;}
    int edp[sz];
    void add(int c,int pos)
    {
        int cur=++cnt,p=lst;lst=cur;a[cur].len=a[p].len+1;edp[cur]=pos;rep(i,0,25) a[cur].ch[i]=0;
        #define v a[p].ch[c]
        while (p&&!v) v=cur,p=a[p].link;
        if (!p) return (void)(a[cur].link=1);
        int q=v;
        if (a[q].len==a[p].len+1) return (void)(a[cur].link=q);
        int t=++cnt;a[t]=a[q];a[t].len=a[p].len+1;a[q].link=a[cur].link=t;edp[t]=edp[cur];
        while (p&&v==q) v=t,p=a[p].link;
    }
}
using namespace SAM;

ll f[26],g[26];

int main()
{
    file();
    read(n);
    rep(i,1,n) { cin>>(s+R[i-1]+1); for (R[i]=L[i]=R[i-1]+1;s[R[i]+1]!='\0';++R[i]); }
    rep(i,1,R[n]) rep(j,0,25) sum[i][j]=sum[i-1][j]+(s[i]=='a'+j);
    drep(t,n,1)
    {
        init();
        rep(i,L[t],R[t]) add(s[i]-'a',i);
        rep(i,0,25) g[i]=0;
        rep(i,2,cnt)
        {
            ll s=1;int p=edp[i];
            rep(k,0,25) if (!a[i].ch[k]) (s+=f[k])%=mod;
            rep(k,0,25) (g[k]+=s*(sum[p-a[a[i].link].len][k]-sum[p-a[i].len][k])%mod)%=mod;
        }
        rep(i,0,25) if (!a[1].ch[i]) (g[i]+=f[i])%=mod;
        rep(i,0,25) f[i]=g[i];
    }
    ll ans=1;
    rep(i,0,25) (ans+=f[i])%=mod;
    cout<<ans;
    return 0;
}

Guess you like

Origin www.cnblogs.com/p-b-p-b/p/11420852.html