回文串
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开始的B 的LCP。
那么显然有:。
为什么呢?考虑从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 }