1. 程式人生 > 實用技巧 >setTimeout和setInterval的區別

setTimeout和setInterval的區別

題目連結

https://ac.nowcoder.com/acm/contest/5667/A

題目大意

定義 f(s , t) 為 s 的字首和 t 的字尾的最大匹配,求$\sum ^{n}_{i=1}\sum ^{n}_{j=1}f\left( s_{i},s_{j}\right) ^{2}$

解題思路

一個很顯然的做法:

先對字串進行 hash , 然後用 cnt 統計每個字串的所有後綴的個數 ,再遍歷每個字串的所有字首統計個數即可

然而我們會發現上述做法會有重複統計的情況 , 如 f ("abab" , "aba")

"abab" 和 "aba" 最大匹配前後綴很顯然是 "aba",但如若我們用上述方法直接統計就會算上 cnt["a"]

而 "a" 為 "aba" 和 "aba" 的最大前後綴匹配(不包含本身) , 也就是 "aba" 在失配情況下得到的次大匹配

這不正是 kmp 的 next 陣列嗎 ?

於是我們只要在每次統計字首 S 時減去這個字首對應 next 陣列的值即可(ans += cnt[S] - cnt[nex[ S ]])

AC_Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
const int base = 233;
const int N = 1e6 + 10
, mod = 998244353; ull power[N] , suf[N]; string s[N]; unordered_map<ull , int>cnt; int n , ans , nex[N] , now[N]; void get_nex(string s , int *nex) { int i = 0 , j = -1 , len = s.size(); nex[i] = j; while(i < len) { while(j != -1 && s[i] != s[j]) j = nex[j]; nex[
++ i] = ++ j ; } } void Hash(string s) { ull suf = 0 , p = 1; for(int i = s.size() - 1 ; i >= 0 ; i --) { suf += p * (s[i] - 'a' + 1); p *= base; cnt[suf] ++ ; } } long long get(int x) { return x * x % mod; } signed main() { ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0); cin >> n; for(int i = 1 ; i <= n ; i ++) { cin >> s[i]; Hash(s[i]); } for(int i = 1 ; i <= n ; i ++) { ull pre = 0 , p = 233; int len = s[i].size(); get_nex(s[i] , nex); for(int j = 0 ; j < len ; j ++) { pre = pre * p + (s[i][j] - 'a' + 1) ; now[j] = cnt[pre]; } for(int j = 0 ; j < len ; j ++) now[nex[j + 1] - 1] -= now[j]; for(int j = 0 ; j < len ; j ++) ans += now[j] * get(j + 1) , ans %= mod; } cout << ans << '\n'; return 0; }