猪猪的难题
猪猪的难题
逆向思维,对于一个字符ch,找到一个不含ch的最大子串,减去这个孙子子串数量,即为答案。
中间的完整片段可以预处理,然后只需要额外处理两端即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1e18;
void solve() {
int n, q; cin >> n >> q;
string s; cin >> s; s = " " + s;
vector<pair<int, int>> query(q);
for(int i = 0; i < q; i ++) {
cin >> query[i].first >> query[i].second;
}
vector<ll> ans(q + 1, 0);
vector<int> cnt(n + 1);
vector<ll> val(n + 1);
vector<int> pos;
for(int c = 0; c < 26; c ++) {
char ch = c + 'a';
pos.clear();
for(int i = 1; i <= n; i ++)
if(s[i] == ch) pos.push_back(i);
int k = pos.size();
if(k == 0) {
for(int j = 0; j < q; j ++) {
auto [l, r] = query[j];
ll len = r - l + 1;
ans[j] += len * (len + 1) / 2;
}
continue;
}
cnt[0] = 0;
for(int i = 1; i <= n; i ++) cnt[i] = cnt[i - 1] + (s[i] == ch);
//计算前缀片段贡献
ll f0 = pos[0];
val[0] = (f0 - 1) * f0 / 2;
for(int j = 1; j < k; j ++) {
ll len = pos[j] - pos[j - 1] - 1;
val[j] = val[j - 1] + len * (len + 1) / 2;
}
ll lenk = n - pos[k - 1];
val[k] = val[k - 1] + lenk * (lenk + 1) / 2;
for(int i = 0; i < q; i ++) {
auto [l, r] = query[i];
int left = cnt[l - 1], right = cnt[r];
//中间没有ch,直接减去完全ch的贡献
if(left == right) {
ll len = r - l + 1;
ans[i] += len * (len + 1) / 2;
}
else {
int firl = pos[left], firh = pos[right - 1];
ll mid = val[right - 1] - val[left];
ll lenleft = firl - l, lenright = r - firh;
ll valb = lenleft * (lenleft + 1) / 2 + lenright * (lenright + 1) / 2;
ans[i] += valb + mid;
}
}
}
for(int i = 0; i < q; i ++) {
auto [l, r] = query[i];
ll len = r - l + 1;
ll tol = len * (len + 1) * 13 - ans[i];
cout << tol << " \n"[i == q - 1];
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _ = 1; cin >> _;
while(_--) solve();
return 0;
}

浙公网安备 33010602011771号