一道字符串题,从前往后压缩句子
每次可以把已有的后缀与带添加的前缀相同的部分压缩掉,问最短压缩后的句子
显然这道题就是要做一个字符串匹配的工作,所以Kmp肯定可以做,但是后来看了一下好像会被卡常数,还是要稍微优化一点的,
这里因为在练hash,所以就用hash做了。
这里我们要的是l,r的哈希值,而且要O(1)获得,不能每次重做,所以就用类似前缀和的思想,开两个数组差分一下就可以(大概是叫这个?)
然后冲浪的时候发现一个很好的板子,正好用上测一下,还可以适用于多哈希。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int maxn=1000005; 6 struct Hash{ 7 int base[4],mod[4]; 8 int tot,hash[4][maxn],pw[4][maxn]; //字符串长度,hash:记从1~i的hash值,pw:记录base^i 9 Hash() { 10 tot=0; 11 for(int i=1;i<=3;i++) pw[i][0]=1; 12 base[1]=233;base[2]=19260817;base[3]=20030714; 13 mod[1]=1e9+7;mod[2]=1e9+9;mod[3]=998244353; 14 } 15 16 void init() { 17 tot=0; 18 } 19 void insert(int c) { 20 tot++; 21 for(int i=1;i<=3;i++) hash[i][tot]=(1LL*hash[i][tot-1]*base[i]+c)%mod[i]; 22 for(int i=1;i<=3;i++) pw[i][tot]=(1LL*pw[i][tot-1]*base[i])%mod[i]; 23 } 24 //字符串[l,r]hash值,type为第几个hash 25 int query(int l,int r,int type) { 26 return (hash[type][r]-(1LL*hash[type][l-1]*pw[type][r-l+1]%mod[type])+mod[type])%mod[type]; 27 } 28 //判断字符串u的[lu,ru]内的字符串和字符串v的[lv,rv]内的字符串是否相同 29 friend bool same(Hash &u,int lu,int ru,Hash &v,int lv,int rv) { 30 if(ru-lu!=rv-lv) return false; 31 for(int i=1;i<=3;i++) if(u.query(lu,ru,i)!=v.query(lv,rv,i)) return false; 32 return true; 33 } 34 }h1,h2; 35 int n; 36 char s[1000005],res[1000005]; 37 int main(){ 38 h1.init(); 39 scanf("%d",&n); 40 int len=0; 41 for (int i=1; i<=n; i++){ 42 scanf("%s",s+1); 43 int l=strlen(s+1); 44 if (i==1){ 45 for (int j=1; j<=l; j++){ 46 h1.insert(s[j]); 47 res[j]=s[j]; 48 } 49 len=l; 50 } 51 else { 52 int p=0; 53 h2.init(); 54 for (int j=1; j<=l; j++){ 55 h2.insert(s[j]); 56 if (same(h1,max(1,h1.tot-j+1),h1.tot,h2,1,h2.tot)) p=j; 57 } 58 for (int j=p+1; j<=l; j++){ 59 h1.insert(s[j]); 60 res[++len]=s[j]; 61 } 62 } 63 } 64 for (int i=1; i<=len; i++) 65 printf("%c",res[i]); 66 }