题目大意
题目描述
定义函数 f(t) 为:将字符串 t 划分为若干部分的最大数量,满足每个部分都是 t 的非空前缀。
There exist k strings p1,p2,…,pk, which are prefixes of t, such that t=p1+p2+…+pk. Here + denotes the string concatenation.
换句话说,f(t) 是满足以下条件的最大正整数 k:存在 k 个字符串 p1,p2,…,pk,它们都是 t 的前缀,且 t=p1+p2+⋯+pk(+ 表示字符串拼接)。
给定一个长度为 n 的小写英文字符串 s。
你需要回答 q 次询问,每次询问给出两个整数 li 和 ri,要求计算并输出:
∑j=lirif(s[li…j])
(其中 s[li…j] 表示 s 从第 li 个字符到第 j 个字符组成的子串)。

这个其实是方便我们进行计算的。
输入格式
第一行包含一个整数 t(1≤t≤103),表示测试用例的数量。
每个测试用例的第一行包含两个整数 n 和 q(1≤n≤106, 1≤q≤100),分别表示字符串长度和询问次数。
第二行包含一个长度为 n 的小写英文字符串 s。
接下来 q 行,每行包含两个整数 li 和 ri(1≤li≤ri≤n),表示一次询问。
保证所有测试用例中 n 的总和不超过 106。
输出格式
对于每次询问,输出一个整数表示表达式的求和结果。
样例数据
1 2 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
| 输入: 6 1 1 a 1 1 5 2 aaaaa 1 5 2 4 6 2 abcdef 1 6 3 5 6 3 abaaba 1 6 1 3 2 6 7 3 abcabca 1 7 2 7 4 7 8 3 aababaac 1 8 2 8 3 7
输出: 1 15 6 6 3 14 4 7 12 9 5 13 14 7
|
样例解释
在第一个测试用例中,f(a)=1。
在第二个测试用例中:
对于第一次询问 1 5:f(a)+f(aa)+f(aaa)+f(aaaa)+f(aaaaa)=1+2+3+4+5=15。
对于第二次询问 2 4(对应的子串是 aaa):f(a)+f(aa)+f(aaa)=1+2+3=6。
在第三个测试用例中:
对于第一次询问 1 6:f(a)+f(ab)+f(abc)+f(abcd)+f(abcde)+f(abcdef)=1+1+1+1+1+1=6。
对于第二次询问 3 5(对应的子串是 cde):f(c)+f(cd)+f(cde)=1+1+1=3。
思路讲解
P3375 【模板】KMP(前缀函数)(完全理解 kmp)
队友的这个思路,确实是非常好啊。

1 2 3 4 5 6 7 8 9 10 11 12 13 14
| vector<ll> shortest_prefix(const vector<ll> &pi) { vector<ll> sp(SZ(pi)); for (int i = 1; i < SZ(pi); ++i) { if (pi[i] == 0) { sp[i] = 0; } else if (sp[pi[i] - 1] > 0) { sp[i] = sp[pi[i] - 1]; } else { sp[i] = pi[i]; } } return sp; }
|
这个方法的正确性还是比较容易看出来的,不言自明,只要前缀和后缀相同。其之所以有效,和 kmp 一样。

AC代码
AC
https://codeforces.com/contest/2209/submission/367859558
源代码
1 2 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
#include <bits/stdc++.h> #define all(vec) vec.begin(),vec.end() #define lson(o) (o<<1) #define rson(o) (o<<1|1) #define SZ(a) ((long long) a.size()) #define debug(var) cerr << #var <<" = ["<<var<<"]"<<"\n"; #define debug1d(a) \ cerr << #a << " = ["; \ for (int i = 0; i < (int)(a).size(); i++) \ cerr << (i ? ", " : "") << a[i]; \ cerr << "]\n"; #define debug2d(a) \ cerr << #a << " = [\n"; \ for (int i = 0; i < (int)(a).size(); i++) \ { \ cerr << " ["; \ for (int j = 0; j < (int)(a[i]).size(); j++) \ cerr << (j ? ", " : "") << a[i][j]; \ cerr << "]\n"; \ } \ cerr << "]\n"; #define cend cerr<<"\n-----------\n" #define fsp(x) fixed<<setprecision(x)
using namespace std;
using ll = long long; using ull = unsigned long long; using DB = double; using i128 = __int128; using CD = complex<double>;
static constexpr ll MAXN = (ll) 1e6 + 10, INF = (1ll << 61) - 1; static constexpr ll mod = 998244353; static constexpr double eps = 1e-8; const double PI = acos(-1.0);
ll lT, testcase;
vector<ll> kmp(const string &A) { vector<ll> pi(SZ(A)); for (int i = 1; i < SZ(A); ++i) { ll len = pi[i - 1]; while (len > 0 && A[len] != A[i]) { len = pi[len - 1]; } if (A[len] == A[i]) { pi[i] = len + 1; } } return pi; }
vector<ll> shortest_prefix(const vector<ll> &pi) { vector<ll> sp(SZ(pi)); for (int i = 1; i < SZ(pi); ++i) { if (pi[i] == 0) { sp[i] = 0; } else if (sp[pi[i] - 1] > 0) { sp[i] = sp[pi[i] - 1]; } else { sp[i] = pi[i]; } } return sp; }
void Solve() { ll N, Q; cin >> N >> Q; string s; cin >> s; for (int _ = 1; _ <= Q; ++_) { ll l, r; cin >> l >> r; auto pi = kmp(string(s.begin() + l - 1, s.begin() + r)); auto sp = shortest_prefix(pi); vector<ll> dp(SZ(pi)); ll ans = 0; for (int i = 0; i < SZ(pi); ++i) { if (sp[i] == 0) { dp[i] = 1; } else { dp[i] = dp[i - sp[i]] + 1; } ans += dp[i]; }
cout << ans << "\n"; } }
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); #ifdef LOCAL cout.setf(ios::unitbuf); #endif
cin >> lT; for (testcase = 1; testcase <= lT; ++testcase) Solve(); return 0; }
|
心路历程(WA,TLE,MLE……)