cf1200 E Compress Words(哈希)
Posted initrain
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf1200 E Compress Words(哈希)相关的知识,希望对你有一定的参考价值。
题意
有n个字符串,记为s1,s2……sn,s2与s1合并,合并的方式为:s1的后缀若与s2的前缀相同,就可以重叠起来,要最长的。
举个例子:
“1333” “33345” → “133345”
s1与s2合并后产生的字符串,再与s3合并,以此类推。
思路
两个字符串的子串匹配,比较容易想到哈希。
一开始想的是从左往右哈希,就是:“123” → 123,但是这样哈希的话,若要更新字符串(就是在末尾添加字符),那么前面每个位置的哈希值都要变,复杂度爆炸。
那就试试从右往左哈希,就是:“123” → 321,这样要在末尾添加字符的时候,前面的哈希值不会变,很好更新。
然后,我们就可以记录当前字符串的最后一个字符是什么,然后遍历下一个要合并进来的字符串,当遇到和末尾相同的字符时,就可以哈希看看能否匹配。
代码
#include <stdio.h> #include <queue> #include <string> #include <string.h> #include <algorithm> #include <math.h> using namespace std; typedef long long int ll; const int maxn = 1e6 + 10; const ll inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll seed = 131; char s[maxn],t[maxn]; ll sval[maxn],tval[maxn],fac[maxn]; int main() { int n,lens,lent; char tail; fac[0] = 1; for(int i = 1;i < maxn;i++){ fac[i] = (fac[i - 1] * seed) % mod; } while(scanf("%d",&n) != EOF){ scanf("%s",s + 1); lens = strlen(s + 1); sval[0] = 0; for(int i = 1;i <= lens;i++){ sval[i] = (((s[i] - ‘0‘) * fac[i - 1]) % mod + sval[i - 1]) % mod; } tail = s[lens]; n--; ll now = 0,pos = 0; while(n--){ now = pos = 0; scanf("%s",t + 1); lent = strlen(t + 1); for(int i = 1;i <= lent;i++){ if(i > lens) break; now = (((t[i] - ‘0‘) * fac[i - 1]) % mod + now) % mod; if(t[i] == tail){ if((now * fac[lens - i]) % mod == ((sval[lens] - sval[lens - i]) % mod + mod) % mod){ pos = i; } } } for(int i = pos + 1;i <= lent;i++){ sval[lens + 1] = (((t[i] - ‘0‘) * fac[lens]) % mod + sval[lens]) % mod; lens++; s[lens] = t[i]; } tail = s[lens]; } s[lens + 1] = 0; printf("%s ",s + 1); } return 0; }
以上是关于cf1200 E Compress Words(哈希)的主要内容,如果未能解决你的问题,请参考以下文章
cf1121F. Compress String(后缀自动机)
CF1120 C. Compress String(SAM+DP)