HDU-4436 str2int 后缀自动机

HDU-4436 str2int

题意

\(n\)个数字串\(s_1,s_2,\dots,s_n\),问有多少个不同的数字(没有前导零)是这\(n\)个数字串中任意一个的子串,求出这些数字的和对2012取模。

\(n\le 10^4,\sum_{i=1}^{n} |s_i|\le 10^5\)

分析

\(n\)个串用一个没出现过的字符连接起来建后缀自动机,后缀自动机上不同路径数即为不同的子串个数,拓扑排序维护答案即可。

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=2e5+10;
const int inf=1e9;
int T,n,m;
char s[N];
struct SAM{
    int last,cnt;int ch[N][11],fa[N],len[N],sum[N],id[N];
    ll g[N],s[N];
    int newnode(){
        ++cnt;
        for(int i=0;i<11;i++) ch[cnt][i]=0;
        return cnt;
    }
    void insert(int c){
        int p=last,np=newnode();last=np;len[np]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else{
                int nq=newnode();len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
    }
    void init(){
        last=cnt=1;
        for(int i=0;i<11;i++) ch[cnt][i]=0;
    }
    ll solve(){
        ll ans=0;
        rep(i,1,cnt) g[i]=s[i]=sum[i]=0;
        rep(i,1,cnt) sum[len[i]]++;
        rep(i,1,cnt) sum[i]+=sum[i-1];
        rep(i,1,cnt) id[sum[len[i]]--]=i;
        s[1]=1;
        rep(i,1,cnt){
            int u=id[i];
            ans=(ans+g[u])%2012;
            for(int j=(u==1);j<10;j++) if(ch[u][j]){
                int x=ch[u][j];
                g[x]=(g[x]+g[u]*10+s[u]*j)%2012;
                s[x]=(s[x]+s[u])%2012;
            }
        }
        return ans;
    }
}sam;
int main(){
    while(~scanf("%d",&m)){
        sam.init();
        for(int i=1;i<=m;i++){
            scanf("%s",s+1);
            int len=strlen(s+1);
            rep(j,1,len) sam.insert(s[j]-'0');
            sam.insert(10);
        }
        printf("%lld\n",sam.solve());
    }
    return 0;
}
posted @ 2020-11-05 00:01  xyq0220  阅读(70)  评论(0编辑  收藏  举报