传送门:https://ac.nowcoder.com/acm/contest/9984/B
题意
给字符串s和t,问有多少种s的两个前缀相连是t的前缀的个数。
思路
首先这题暴力n^2肯定会T的。 正确解法是先找s的前缀s1和t的前半部分配对,再找s的最长前缀s2和t的后半部分配对,贡献为s2的长度。
如何配对? 区间字符串哈希!
关于字符串哈希,就是将一个区间的字符段用一个整数表示,在没有哈希冲突的情况下,这个整数就代表独一无二的字符段。
如何找最长前缀? 二分!
Code
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 
 | ##include "bits/stdc++.h"
 using namespace std;
 typedef unsigned long long ull;
 
 const ull mod = 131;
 const int N = 1e5 + 10;
 ull p[N];
 ull sums[N], sumt[N];
 char s[N], t[N];
 int lens, lent;
 
 ull hashs(int l, int r) {
 return sums[r] - sums[l - 1] * p[r - l + 1];
 }
 
 ull hasht(int l, int r) {
 if(r > lent) return 0;
 return sumt[r] - sumt[l - 1] * p[r - l + 1];
 }
 
 void solve() {
 cin >> (s + 1) >> (t + 1);
 lens = strlen(s + 1), lent = strlen(t + 1);
 p[0] = 1;
 for(int i = 1;i <= max(lens, lent); i++) {
 if(i <= lens) sums[i] = sums[i - 1] * mod + s[i];
 if(i <= lent) sumt[i] = sumt[i - 1] * mod + t[i];
 p[i] = p[i - 1] * mod;
 }
 
 ull ans = 0;
 for(int i = 1;i <= lent - 1; i++) {
 if(s[i] != t[i]) break;
 if(t[i + 1] != s[1]) continue;
 int l = 1, r = lens, res = 0;
 while(l <= r) {
 int mid = (l + r) / 2;
 if(hashs(1, mid) == hasht(i + 1, i + mid)) {
 res = mid; l = mid + 1;
 }
 else r = mid - 1;
 }
 ans += res;
 }
 cout << ans << endl;
 }
 
 signed main() {
 solve();
 }
 
 | 
本文作者:jujimeizuo
本文地址: https://blog.jujimeizuo.cn/2021/02/19/2021-nowcoder-hanjia-4-b/ 
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!