您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: