hdu4436 str2int 后缀自动机 SAM
2013-10-16 15:30
351 查看
给n个串,求这n个串的的不同子串表示的数字的和对2012取模...看到关于什么子串,后缀的第一反应应该就是后缀数组或者后缀自动机..10^5的规模,SA,SAM应该都能做,SAM应该好像点。把n各串用某拼接符连起来建立一个SAM,因为在SAM上跑一边可以求出这个串的所有子串,所以可以利用这个性质来求不同子串的和。先做一个拓扑排序,然后从前到后扫一遍,每个状态维护两个值cnt,sum分别表示到达该状态的方案数和当前的子串和,每次枚举一条转移边,假设这条边从p到q,那么就执行q.cnt+=p.cnt,q.sum+=p.sum*10+转移边*p.cnt;最后统计一下就行了。
#include <iostream> #include <algorithm> #include <cstdio> #include <memory.h> #include <string> #include <cstring> using namespace std; typedef long long ll; const int maxn=100000+50000; const int S=11; const int mod=2012; int tot,len; int n,m; int wtop[maxn<<1]; int c[maxn<<1]; int k; int ans; struct node { node *par,*go[S]; int val,id,cnt,sum; }*tail,*root,que[maxn<<1],*top[maxn<<1]; char str[maxn],s[maxn],ss[maxn]; struct SAM { void init() { memset(que,0,sizeof que); tot=0; len=1; root=tail=&que[tot++]; root->id=root->sum=root->cnt=0; ans=0; } void add(int c,int l) { node* p=tail; node* np=&que[tot++]; np->val=l; np->id=tot-1; np->cnt=np->sum=0; while(p && p->go[c]==NULL) p->go[c]=np,p=p->par; if (p==NULL) np->par=root; else { node* q=p->go[c]; if (p->val+1==q->val) np->par=q; else { node *nq=&que[tot++]; *nq=*q; nq->id=tot-1; nq->val=p->val+1; np->par=q->par=nq; nq->cnt=nq->sum=0; while(p && p->go[c]==q) p->go[c]=nq,p=p->par; } } tail=np; } void debug_suff() { for (int i=0; i<tot; i++) { for (int c=0; c<S; c++) if (que[i].go[c]) { cout<<que[i].id<<" "<<que[i].go[c]->id<<endl; } } } void debug_pre() { for (int i=1; i<tot; i++) { cout<<que[i].id<<" "<<que[i].par->id<<endl; } } void TopS() { memset(c,0,sizeof c); for (int i=0; i<tot; i++) c[que[i].val]++; for (int i=1; i<len; i++) c[i]+=c[i-1]; for (int i=0; i<tot; i++) top[--c[que[i].val]]=&que[i],wtop[c[que[i].val]]=i; } int slove() { TopS(); node *p,*q; root->cnt=1; root->sum=0; int res=0; for (int i=0; i<tot; i++) { p=top[i]; for (int j=0; j<10; j++) if (i==0 && j==0) continue; else { if (p->go[j]) { q=p->go[j]; q->cnt+=p->cnt; q->cnt%=mod; q->sum+=(p->sum*10+p->cnt*j); q->sum%=mod; } } // res+=p->sum; // res%=mod; } for (int i=0; i<tot; i++) { res+=que[i].sum; res%=mod; } return res; } }sam; int main() { // freopen("in.txt","r",stdin); while(~scanf("%d",&n)) { sam.init(); for (int i=1; i<=n; i++) { scanf("%s",str); int ll=strlen(str); for (int j=0; j<ll; j++) sam.add(str[j]-'0',len++); sam.add(10,len++); } cout<<sam.slove()<<endl; } return 0; }
相关文章推荐
- [hdu4436 str2int]后缀自动机SAM(或后缀数组SA)
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- hdu4436-str2int(后缀数组 or 后缀自动机)
- 后缀自动机SAM
- poj 3415 SAM后缀自动机
- 后缀自动机(SAM):SPOJ Longest Common Substring II
- 后缀自动机(SAM)模板
- codeoforces 271 D (后缀自动机 SAM)
- SPOJ 1811. Longest Common Substring (LCS,两个字符串的最长公共子串, 后缀自动机SAM)
- 后缀自动机模板 SAM
- [转]后缀自动机(SAM)
- HDU 4622 Reincarnation(SAM 后缀自动机 求子串的不同子串个数)
- SAM 后缀自动机——学习笔记
- 后缀自动机(SAM)模板
- SAM(后缀自动机)模板
- HDU 4436 str2int(后缀自动机)
- hdu 4436 str2int (后缀自动机+dp)
- 后缀自动机(SAM)学习小记
- HDU 3518 Boring counting(后缀自动机 SAM)