您的位置:首页 > 其它

UVA1673 str2int(SAM)

2016-03-17 20:46 411 查看
【题目链接】

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51267

【题意】

给定n个字符串,计算所有忽略前导0的子串形成的不重整数之和。

【思路】

既然是处理子串问题,我们可以合并串之后构造一个SAM。

SAM的性质:结点u代表的字符串集是从根到u路径上的所有结点代表的字符串集之并,结点u所代表的字符串集为最长串的所有子串。

记cnt[u]为状态u代表的字符串个数,sum[u]代表状态u代表的字符串对应的数之和。

拓扑排序后,设p为当前结点,trans(p,j)为np,则有:

cnt[np]+=cnt[p]

sum[np]+=sum[p]*10+cnt[p]*j

不走$边,第一次不走0边。

【代码】

#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

typedef long long ll;
const int N = 2e5+10;
const int MOD = 2012;

int n,len;
char s
;
int sum
,cnt
;
int sz,last,fa
,ch
[11],l
,c
,b
;

void add(int c)
{
int p=last,np=++sz; last=np;
l[np]=l[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(l[q]==l[p]+1) fa[np]=q;
else {
int nq=++sz; l[nq]=l[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()
{
sz=last=1;
len=0;
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
memset(ch,0,sizeof(ch));
memset(c,0,sizeof(c));
memset(fa,0,sizeof(fa));
memset(l,0,sizeof(l));
}
int main()
{
while(scanf("%d",&n)==1)
{
init();
FOR(i,1,n) {
scanf("%s",s);
if(i!=1) add(10),len++;
for(int j=0;s[j];j++)
add(s[j]-'0'),len++;
}
FOR(i,1,sz) c[l[i]]++;
FOR(i,1,len) c[i]+=c[i-1];
FOR(i,1,sz) b[c[l[i]]--]=i;

int ans=0;
cnt[1]=1;
FOR(i,1,sz) {
int p=b[i];
for(int j=0;j<10;j++) {
if(i==1&&j==0) continue;
if(ch[p][j]) {
int np=ch[p][j];
cnt[np]=(cnt[np]+cnt[p])%MOD;
sum[np]=(sum[np]+sum[p]*10+cnt[p]*j)%MOD;
}
}
ans=(ans+sum[p])%MOD;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: