All with Pairs
题意
记为最大的使得
给个串,求
题解
统计所有串每一个后缀出现次数,这个可以用哈希来实现
map<ull, int> mp; void insert(string &s) { ull hash = 0, b = 1;//unsigned long long就可以自然溢出 for (int i = s.length() - 1; i >= 0; i--, b *= base) { hash += b * (s[i] - 'a' + 1); mp[hash]++; } }
对于一个串来说,记为所有串中后缀等于的数量
那么串的贡献就是
这里有一个问题,如果我们按上面的方法来求得所有串每一个后缀出现次数
会有重复计算,如的后缀有, 如果我们当前串能够匹配的最大长度为,即匹配的串为时, 这个串也一定是匹配的,所以要对进行容斥
容斥只需要从前往后令即可
因为如果从后往前容斥就要不断跳数组,前面每一个重复的串都要减去的贡献
但是正向进行就只用减一次,因为中,本就包含了后面重复的贡献
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int MAX = 1e5 + 10; const int base = 233; const int mod = 998244353; vector<int> getNext(string &s) { int n = s.length(); vector<int> nxt(n); for (int i = 1; i < n; i++) { int j = nxt[i - 1]; while (j > 0 && s[i] != s[j]) j = nxt[j - 1]; if (s[i] == s[j]) j++; nxt[i] = j; } return nxt; } map<ull, int> mp; void insert(string &s) { ull hash = 0, b = 1;//unsigned long long就可以自然溢出 for (int i = s.length() - 1; i >= 0; i--, b *= base) { hash += b * (s[i] - 'a' + 1); mp[hash]++; } } int N; string s[MAX]; int cnt[MAX * 10]; int main() { cin >> N; for (int i = 1; i <= N; i++) { cin >> s[i]; insert(s[i]); } ll ans = 0; for (int i = 1; i <= N; i++) { vector<int> nxt = getNext(s[i]); ull hash = 0; for (int j = 0; j < s[i].length(); j++) { hash = hash * base + s[i][j] - 'a' + 1; cnt[nxt[j]] -= (cnt[j + 1] = mp[hash]); //我这里j是从0开始的, 但是cnt数组是从1开始的,有点不一样 } for (int j = 1; j <= s[i].length(); j++) ans = (ans + 1ll * cnt[j] * j % mod * j % mod) % mod; } printf("%lld\n", ans); return 0; }