hdu4436 SAM_多串匹配
2014-06-22 12:47
381 查看
题目链接:Click here
将多个串合并到一起,中间用一个符号分割就好了。 如果选用的是10来分割, 则最后计算的时候只用计算节点 0至于9就可以了。
有一点需要注意。 对于前导0 , 可以在读入的时候就处理掉,不添加这个节点,也可以在最后拓扑排序的时候处理掉。
如果不处理这个前导0, 则会多计算一部分的后缀,导致结果变大。
cnt是记录这个重复串出现了几次。
0 0拓扑排序从根节点开始进行遍历下去。
将多个串合并到一起,中间用一个符号分割就好了。 如果选用的是10来分割, 则最后计算的时候只用计算节点 0至于9就可以了。
有一点需要注意。 对于前导0 , 可以在读入的时候就处理掉,不添加这个节点,也可以在最后拓扑排序的时候处理掉。
如果不处理这个前导0, 则会多计算一部分的后缀,导致结果变大。
cnt是记录这个重复串出现了几次。
0 0拓扑排序从根节点开始进行遍历下去。
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int MAX_NODES = 411111; const int N = 221111; struct node{ struct node *ch[12]; struct node *f; int mx; int sum,cnt; void init(){ memset(ch,0,sizeof(ch)); f = 0; cnt = sum = 0; } }*root,*cnt,*tail,pool[MAX_NODES]; int n; char s ; void init(){ root = cnt = tail = pool ; root ->init(); cnt++; } void add(int c,int len){ node *p = tail, *np = cnt++; np->init(); for( ; p && !p->ch[c] ; p = p->f) p->ch[c] = np; np->mx = len; tail = np; if(!p) np->f = root; else if( p->ch[c]->mx == p->mx+1) np->f = p->ch[c]; else{ node *q = p->ch[c], *r = cnt++; *r = *q; r->mx = p->mx+1; q->f = np->f = r; for( ; p && p->ch[c] == q ; p = p->f) p->ch[c] = r; } } int rc , top ; int so ; bool cmp(int a,int b){ return pool[a].mx < pool[b].mx; } const int MOD = 2012; int main(){ while(scanf("%d",&n)!=EOF){ init(); int pre = 0; for(int i = 0;i < n;i++){ scanf("%s",s); for(int j = 0; s[j] ;j++){ add(s[j]-'0',++pre); } if(i+1<n) add(10,++pre); } memset(rc,0,sizeof(rc)); int tot = cnt - root; //for(int i = 0;i < tot;i++){ // printf("pool[%d]=%d\n",i,pool[i].mx); //} for(int i = 0;i < tot; i++) rc[pool[i].mx]++; for(int i = 1;i < tot; i++) rc[i] += rc[i-1]; for(int i = tot-1;i > 0;i--) top[--rc[pool[i].mx]] = i; //for(int i = 0;i < tot;i++) // so[i] = i; //sort(so,so+tot,cmp); int ans = 0; pool[0].cnt = 1; for(int i = 0;i < tot;i++){ node * q = &pool[top[i]]; //printf("top[%d]=%d\n",i,top[i]); //node *q = &pool[so[i]]; if(i > 0 && !q->cnt) continue; ans = (ans + q->sum ) % MOD; //printf("q->sum = %d\n",q->sum); //printf("ans=%d\n",ans); for(int j = 0;j < 10;j++){ if(i==0 && j == 0)continue; // 去掉前导0 if(q->ch[j]){ q->ch[j]->sum = (q->ch[j]->sum + q->sum*10 + q->cnt * j) % MOD; q->ch[j]->cnt += q->cnt; //printf("q->ch[%d]->cnt=%d\n",j,q->ch[j]->cnt); //printf("q->ch[%d]->sum=%d\n",j,q->ch[j]->sum); } } } printf("%d\n",ans); } return 0; }
相关文章推荐
- [hdu4436 str2int]后缀自动机SAM(或后缀数组SA)
- hdu4436 str2int 后缀自动机 SAM
- 为什么 Kotlin 调用 java 时可以使用 Lambda? —— SAM 转换机制的介绍
- 计蒜客-易张彪 字符串匹配KMP
- KMP-字符串匹配
- UVA 11419 SAM I AM
- 子串总个数 顺带sam 模版
- Periodic Strings 字符串匹配
- JAVA中字符串匹配indexof()的用法
- 201409-3 字符串匹配 ccf
- 生信:2:sam格式文件解读
- 【算法专题】后缀自动机SAM
- 利用字符串匹配,截取图片链接,爬取nba百度贴吧
- Java 字符串匹配算法
- 北航研究生复试2008上机第三题:字符串匹配
- 洛谷P3375 - 【模板】KMP字符串匹配
- CCF考试——201409-3字符串匹配
- 数字串匹配
- UVA -11419 SAM I AM 最小边覆盖输出路径
- 字符串匹配(二)——Trie:字典树