HDU 4622 Reincarnation
2015-06-24 02:55
363 查看
题目大意:
给定一个基础字符串,再给多个字符串,求出基础字符串中能得到的不一样的子串的个数未出现在后面多个字符串当中
这里以基础子串构建后缀自动机是没问题的
后面的多个子串不断在后缀自动机上进行匹配,每次到达一个状态点,就要更新当前点所能达到的其他字符串抵达最大长度 mx,那么未能匹配的长度就是cur->l-mx
因为父节点受子节点影响,所以要拓扑排序,不断更新父节点所能达到的最大长度,最后统计所有数量之和即可
给定一个基础字符串,再给多个字符串,求出基础字符串中能得到的不一样的子串的个数未出现在后面多个字符串当中
这里以基础子串构建后缀自动机是没问题的
后面的多个子串不断在后缀自动机上进行匹配,每次到达一个状态点,就要更新当前点所能达到的其他字符串抵达最大长度 mx,那么未能匹配的长度就是cur->l-mx
因为父节点受子节点影响,所以要拓扑排序,不断更新父节点所能达到的最大长度,最后统计所有数量之和即可
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define N 100010 #define ll long long struct SamNode{ SamNode *son[26] , *f; int l , mx; void init(){ for(int i=0 ; i<26 ; i++) son[i] = NULL; f=NULL; l = mx = 0; } }sam[N<<1] , *root , *last , *b[N<<1]; int cnt , num ; ll ret; char s ; void add(int x) { SamNode *p = &sam[++cnt] , *jp = last; p->init(); p->l = jp->l+1 ; last = p; for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p; if(!jp) p->f = root; else{ if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x]; else{ SamNode *r = &sam[++cnt] , *q = jp->son[x]; r->init(); *r = *q; r->l = jp->l+1; p->f = q->f = r; for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x]=r; } } } void solve(int n , int &cas) { int l , len=strlen(s); memset(num , 0 , sizeof(num)); for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++; for(int i=1 ; i<=len ; i++) num[i]+=num[i-1]; for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]]=&sam[i]; for(int i=0 ; i<n ; i++){ scanf("%s" , s); l=strlen(s) , len=0; //len表示当前所能达到的最大长度 SamNode *cur = root; for(int j=0 ; j<l ; j++){ int x = s[j]-'a'; if(cur->son[x]){ len++; cur = cur->son[x]; cur->mx = max(cur->mx , len); }else{ while(cur&&!cur->son[x]) cur=cur->f; if(!cur) cur = root , len=0; else{ len = cur->l+1; cur = cur->son[x]; cur->mx = max(cur->mx , len); } } } } ll ret = 0; for(int i=cnt ; i>=1 ; i--){ // cout<<i<<" "<<b[i]->l<<" "<<b[i]->mx<<endl; if(b[i]->mx) ret = ret + (b[i]->l-b[i]->mx>=0?b[i]->l-b[i]->mx:0); else ret = ret + b[i]->l-b[i]->f->l; b[i]->f->mx = max(b[i]->f->mx , b[i]->mx); } printf("Case %d: %I64d\n" , ++cas , ret); } int main() { // freopen("a.in" , "r", stdin); int T , n , cas=0; scanf("%d" , &T); while(T--) { scanf("%d%s" , &n , s); int l = strlen(s); sam[0].init(); root = last = &sam[cnt=0] , ret = 0; for(int i=0 ; i<l ; i++) add(s[i]-'a'); solve(n , cas); } return 0; }
相关文章推荐
- Xming + PuTTY 在Windows下远程Linux主机
- Xming + PuTTY 在Windows下远程Linux主机
- Codeforces Round #306 (Div. 2) 题解
- tomcat - set up username and password
- post 传字典
- 笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-10 可编程对象
- dedecms调用子栏目内容,缩略图,以及栏目名字
- hdu 2680 Choose the best route
- swift版本hello
- 直方图均衡化原理之概率论相关知识
- iOS-图片的拉伸
- 加载3D模型时注意事项
- Qt热点
- Ubuntu12.04下WiFi热点配置
- jQuery选择器
- E: Unable to correct problems, you have held broken packages.
- linux 的有用的网站
- HDU 4622 求解区间字符串中的不同子串的个数
- nodeJS链接mysql数据库(express框架)
- vector容器常用方法