Foreign回文串 [hash]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Foreign回文串 [hash]相关的知识,希望对你有一定的参考价值。

回文串

Time Limit: 10 Sec  Memory Limit: 256 MB

Description

  ASDFZ 的机房中不仅有红太阳,还有蓝太阳和原谅色太阳。

  有一天,太阳们来到机房,发现桌上有不知 道哪个蒟蒻放上的问题:
    令 F (A,B) 表示选择一个串 A 的非空前缀 S 和串 B 的非空后缀 T 使得将串 S 和串 T 拼起来之后是回 文串的方案数。
    现在给定两个串 A 和 B,令 Ai 表示串 A 的第 i 长的后缀,Bi 为串 B 的第 i 长的前缀。

  有 Q 组询问,第 i 组询问给定 xi 和 yi,对每组询问求 F (Axi,Byi) 的值。
  太阳们非常强,自然不会把时间花在这种水题上。快来做做这个题呀。

Input

  第一行一个字符串 str,表示数据类型。
  接下来的两行分别表示字符串 A 和 B。
  接下来一行一个正整数 Q,表示询问的个数。
  接下来 Q 行,每行两个正整数 xi 和 yi。

Output

  输出 Q 行,每行一个整数,表示这一组询问的答案。

Sample Input

  B
  newionyzz
  wyxioiwen
  1
  1 1

  技术分享

Sample Output

  16

HINT

  技术分享

  技术分享

Solution

  显然,我们先将B串倒置,然后答案显然与 以某一位开始的回文串个数 有关(后面有说明),记*F表示这个东西。

  那么这个东西,我们显然可以 枚举中间位置x,然后 字符串hash + 二分 得到 以 c 为中间位置最长回文子串的L、R

  那么贡献显然是:[L, x]这一段的 F 每一个+1。这样我们就得到了 F 数组,对于 B 做相同处理,就得到了 G 数组(性质与F一样)。

  考虑怎么统计答案,我们先用字符串hash + 二分得到 以x开始的A以y开始的BLCP

  那么显然有:技术分享

  为什么呢?考虑从LCP中取出一位,那么显然形如:a__a,中间可以填的就是以后面某一位开始的F or G

  为什么要加上l呢?因为这就是中间不填的个数。注意不能加上F[x] or G[y],因为形如a__a,不能没有头尾的a。

  这样我们就AC了这道题啦!

  (QAQ 万恶的出题人最后3分是卡自然溢出hash的!)。

Code

技术分享
  1 #include<iostream>    
  2 #include<string>    
  3 #include<algorithm>    
  4 #include<cstdio>    
  5 #include<cstring>    
  6 #include<cstdlib>
  7 #include<cmath>
  8 #include<vector>
  9 using namespace std;  
 10 typedef long long s64;
 11  
 12 const int ONE = 800005;
 13 const int Base = 10007;
 14 const int MOD = 1e9 + 7;
 15 
 16 int n, m, Q;
 17 int x, y;
 18 char c[5], A[ONE], B[ONE];
 19 int Pow[ONE];
 20 int pre_A[ONE], pre_B[ONE], suc_A[ONE], suc_B[ONE];
 21 s64 F[ONE], G[ONE];
 22 s64 Sum_F[ONE], Sum_G[ONE];
 23 
 24 struct power
 25 {
 26         int l, r;
 27 };
 28 
 29 int get()
 30 {    
 31         int res=1,Q=1;char c;    
 32         while( (c=getchar())<48 || c>57 ) 
 33         if(c==-)Q=-1; 
 34         res=c-48;     
 35         while( (c=getchar())>=48 && c<=57 )    
 36         res=res*10+c-48;
 37         return res*Q;
 38 }
 39 
 40 void Deal_first()
 41 {
 42         Pow[0] = 1;
 43         for(int i = 1; i <= max(n, m); i++)
 44             Pow[i] = (s64)Pow[i - 1] * Base % MOD;
 45         for(int i = 1; i <= n; i++) pre_A[i] = (s64)pre_A[i - 1] * Base % MOD + A[i];
 46         for(int i = 1; i <= n; i++) suc_A[i] = (s64)suc_A[i - 1] * Base % MOD + A[n - i + 1];
 47         for(int i = 1; i <= m; i++) pre_B[i] = (s64)pre_B[i - 1] * Base % MOD + B[i];
 48         for(int i = 1; i <= m; i++) suc_B[i] = (s64)suc_B[i - 1] * Base % MOD + B[m - i + 1];
 49 }
 50 
 51 int Pre(int PD, int l, int r)
 52 {
 53         if(PD == 1) return (pre_A[r] - (s64)pre_A[l - 1] * Pow[r - l + 1] % MOD + MOD) % MOD; 
 54         if(PD == 2) return (pre_B[r] - (s64)pre_B[l - 1] * Pow[r - l + 1] % MOD + MOD) % MOD;
 55 }
 56 
 57 int Suc(int PD, int L, int R)
 58 {
 59         int Limit = PD == 1 ? n : m;
 60         int l = Limit - R + 1, r = Limit - L + 1; 
 61         if(PD == 1) return (suc_A[r] - (s64)suc_A[l - 1] * Pow[r - l + 1] % MOD + MOD) % MOD;
 62         if(PD == 2) return (suc_B[r] - (s64)suc_B[l - 1] * Pow[r - l + 1] % MOD + MOD) % MOD;
 63 }
 64 
 65 int Check(int PD, int l, int r)
 66 {
 67         int Limit = PD == 1 ? n : m;
 68         if(l < 1 || r > Limit) return 0;
 69         return Pre(PD, l, r) == Suc(PD, l, r);
 70 }
 71 
 72 power Find(int PD, int PosA, int PosB)
 73 {
 74         int l = 1, r = PD == 1 ? n : m;
 75         while(l < r - 1)
 76         {
 77             int mid = l + r >> 1;
 78             int Left = PosA - mid + 1, Right = PosB + mid - 1;
 79             if(Check(PD, Left, Right)) l = mid;
 80             else r = mid;
 81         }
 82         
 83         int Left, Right;
 84         Left = PosA - r + 1, Right = PosB + r - 1;
 85         if(Check(PD, Left, Right)) return (power) {Left, Right};
 86         
 87         Left = PosA - l + 1, Right = PosB + l - 1;
 88         return (power) {Left, Right};
 89 }
 90 
 91 void Deal_F()
 92 {
 93         for(int i = 1; i <= n; i++)
 94         {
 95             power pos;
 96             pos = Find(1, i, i);
 97             F[pos.l]++, F[i + 1]--;
 98             if(A[i] != A[i + 1]) continue;
 99             
100             pos = Find(1, i, i + 1);
101             F[pos.l]++, F[i + 1]--;
102         }
103         for(int i = 1; i <= n + 1; i++) F[i] += F[i - 1];
104         for(int i = 1; i <= n + 1; i++) Sum_F[i] = Sum_F[i - 1] + F[i];
105 }
106 
107 void Deal_G()
108 {
109         for(int i = 1; i <= m; i++)
110         {
111             power pos;
112             pos = Find(2, i, i);
113             G[pos.l]++, G[i + 1]--;
114             if(B[i] != B[i + 1]) continue;
115             
116             pos = Find(2, i, i + 1);
117             G[pos.l]++, G[i + 1]--;
118         }
119         for(int i = 1; i <= m + 1; i++) G[i] += G[i - 1];
120         for(int i = 1; i <= m + 1; i++) Sum_G[i] = Sum_G[i - 1] + G[i];
121 }
122 
123 int Get_LCP(int L1, int L2)
124 {
125         int l = 0, r = min(n - L1 + 1, m - L2 + 1);
126         
127         while(l < r - 1)
128         {
129             int mid = l + r >> 1;
130             
131             if(Pre(1, L1, L1 + mid - 1) == Pre(2, L2, L2 + mid - 1)) l = mid;
132             else r = mid;
133         }
134         
135         if(Pre(1, L1, L1 + r - 1) == Pre(2, L2, L2 + r - 1)) return r;
136         return l;
137 }
138 
139 int main()
140 {
141         scanf("%s", c + 1);
142         scanf("%s", A + 1);    n = strlen(A + 1);
143         scanf("%s", B + 1); m = strlen(B + 1);
144         for(int i = 1, j = m; i <= j; i++, j--) swap(B[i], B[j]);
145         Deal_first();
146         Deal_F();    Deal_G();
147         
148         Q = get();
149         while(Q--)
150         {
151             x = get(), y = get();
152             int l = Get_LCP(x, y);
153             s64 Ans = Sum_F[x + l] - Sum_F[x] + Sum_G[y + l] - Sum_G[y] + l
154             printf("%lld\\n", Ans);
155         }
156 }
View Code

 

以上是关于Foreign回文串 [hash]的主要内容,如果未能解决你的问题,请参考以下文章

Extend to Palindrome (顺序Hash和逆序Hash处理回文)

AcWing 139 回文子串的最大长度(二分,hash ver.)

HDU 6599 I Love Palindrome String (回文树+hash)

POJ--3974 Palindrome(回文串,hash)

bzoj 2124 等差子序列 树状数组维护hash+回文串

[CSP-S模拟测试]:回文(hash+二维前缀和)