bzoj4566 [Haoi2016]找相同字符
地址:http://www.lydsy.com/JudgeOnline/problem.php?id=4566
题目:
4566: [Haoi2016]找相同字符
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 600 Solved: 329
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabb
bbaa
bbaa
Sample Output
10
思路:
对第一个串建立后缀自动机,然后让第二个串在sam上跑。
对于每个走到的状态p,fa[p]状态代表的后缀集合必然出现过,且p状态的长度为now-len[fa[p]](now为走到该状态的匹配长度)
对于状态p,如果endpos(p)内的后缀全部出现过,则贡献为|endpos(p)|*(len[p]-len[fa[p]]),且要用fa[p]去更新p.
把每个点的贡献记为sum[p]。
则走到状态p,ans+=sum[fa[p]]+|endpos(p)|*(now-len[fa])。
1 /************************************************************** 2 Problem: 4566 3 User: weeping 4 Language: C++ 5 Result: Accepted 6 Time:2072 ms 7 Memory:50120 kb 8 ****************************************************************/ 9 10 #include <bits/stdc++.h> 11 12 using namespace std; 13 14 struct SAM 15 { 16 static const int MAXN = 200002<<1;//大小为字符串长度两倍 17 static const int LetterSize = 26; 18 19 int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN]; 20 int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组 21 22 void init( void) 23 { 24 last = tot = 1; 25 len[1] = 0; 26 memset(ch,0,sizeof ch); 27 memset(fa,0,sizeof fa); 28 memset(cnt,0,sizeof cnt); 29 } 30 31 void add( int x) 32 { 33 int p = last, np = last = ++tot; 34 len[np] = len[p] + 1, cnt[last] = 1; 35 while( p && !ch[p][x]) ch[p][x] = np, p = fa[p]; 36 if( p == 0) 37 fa[np] = 1; 38 else 39 { 40 int q = ch[p][x]; 41 if( len[q] == len[p] + 1) 42 fa[np] = q; 43 else 44 { 45 int nq = ++tot; 46 memcpy( ch[nq], ch[q], sizeof ch[q]); 47 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq; 48 while( p && ch[p][x] == q) ch[p][x] = nq, p = fa[p]; 49 } 50 } 51 } 52 53 void toposort( void) 54 { 55 for(int i = 1; i <= len[last]; i++) sum[i] = 0; 56 for(int i = 1; i <= tot; i++) sum[len[i]]++; 57 for(int i = 1; i <= len[last]; i++) sum[i] += sum[i-1]; 58 for(int i = 1; i <= tot; i++) tp[sum[len[i]]--] = i; 59 for(int i = tot; i; i--) cnt[fa[tp[i]]] += cnt[tp[i]]; 60 } 61 62 void work(char *ss) 63 { 64 long long ans=0; 65 for(int i = 1; i <= tot; i++) 66 sum[tp[i]]=sum[fa[tp[i]]]+cnt[tp[i]]*(len[tp[i]]-len[fa[tp[i]]]); 67 for(int i=0,n=strlen(ss),p=1,num=0;i<n;i++) 68 { 69 int c=ss[i]-'a'; 70 if(ch[p][c]) p=ch[p][c],num++; 71 else 72 { 73 while(p&&!ch[p][c]) p=fa[p]; 74 if(!p) p=1,num=0; 75 else num=len[p]+1,p=ch[p][c]; 76 } 77 ans+=sum[fa[p]]+1LL*cnt[p]*(num-len[fa[p]]); 78 } 79 printf("%lld\n",ans); 80 } 81 } sam; 82 83 char sa[200005],sb[200005]; 84 85 int main( void) 86 { 87 scanf("%s%s",sa,sb); 88 sam.init(); 89 for(int i=0,len=strlen(sa);i<len;i++) sam.add(sa[i]-'a'); 90 sam.toposort(),sam.work(sb); 91 return 0; 92 }
作者:weeping
出处:www.cnblogs.com/weeping/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。