Codeforces Round 934 2D/1B

Link

场上思路出的最快的一题,但没调出来

反着考虑全为回文串需满足哪些情况。

\(k = 1\),没有限制条件。

\(k = 2\),对于任意三个位置 _ _ _,先填 \(x\) \(x\) _,然后二三也要回文,第三位只能是 \(x\),最终整段区间全部相同。

\(k = 3\),全部相同的情况肯定满足,考虑出现不同元素:

  • _ _ _ _
  • \(x\) _ \(x\) _
  • \(x\) \(y\) \(x\) _

此时二到四段也要回文,最终 \(x\) \(y\) \(x\) \(y\) 交替出现。

以此类推 \(k > 3\) 的情况,得到结论:

奇数需间隔排列或全相等,偶数只能全相等

此处有一特殊情况,若 \(k = r - l + 1\),那么只要整段不回文,就有 \(r - l + 1\) 的贡献。

如何快速判断区间全部相等?

只需维护 \(lst[i]\) 表示前一个与 \(s[i]\) 不同的元素的位置,最后判断 \(lst[r] < l\)
具体实现:

	vector<int> lst(n, -1);
	for(int i = 1; i < n; ++ i) {
		if(s[i] != s[i - 1]) lst[i] = i - 1;
		else lst[i] = lst[i - 1];
	}

如何快速判断元素交替出现?

维护 \(f[i][pre]\) 表示从 \(i\) 起,前一位的值是 \(pre\) 的交替段向左延伸的最大长度。

这里再维护一个 \(L[i] = i - f[i][s[i - 1]] + 1\) 得到区间左端点,判断 \(L[r] <= l\)

	vector<vector<int>> f(n, vector<int>(128, 1));
	vector<int> L(n, 0);
	for(int i = 1; i < n; ++ i) {
		f[i][s[i - 1]] = 1 + f[i - 1][s[i]];
		L[i] = i - f[i][s[i - 1]] + 1;
	}

如何判断区间是否回文?

可以 \(manacher\),但我不会,这里用字符串哈希解决。

代码:

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
using namespace std;
using ll = unsigned long long;
constexpr int N = 2e5 + 5, B = 131, P = 1e9 + 7;

ll pre[N], pw[N] = {1};
ll h[N], t[N];
ll H(int l, int r) {return (h[r] - (h[l - 1] * pw[r - l + 1]) % P + P) % P;}
ll T(int l, int r) {return (t[r] - (t[l - 1] * pw[r - l + 1]) % P + P) % P;}

void init(ll *a, string &s) {
	a[0] = s[0];
	for(int i = 1; i < s.length(); ++ i) {
		a[i] = (a[i - 1] * B + s[i]) % P; 
	}
}

void solve() {
	int n, m; cin >> n >> m;
	string s; cin >> s;
	string _ = s;
	reverse(_.begin(), _.end());
	init(h, s);
	init(t, _);
	
	vector<int> lst(n, -1);
	for(int i = 1; i < n; ++ i) {
		if(s[i] != s[i - 1]) lst[i] = i - 1;
		else lst[i] = lst[i - 1];
	}
	
	vector<vector<int>> f(n, vector<int>(128, 1));
	vector<int> L(n, 0);
	for(int i = 1; i < n; ++ i) {
		f[i][s[i - 1]] = 1 + f[i - 1][s[i]];
		L[i] = i - f[i][s[i - 1]] + 1;
	}
	
	for(int i = 0; i < m; ++ i) {
		int l, r; cin >> l >> r;
		-- l, -- r;
		if(lst[r] < l) cout << 0 << '\n';
		else {
			ll len = r - l + 1;
			ll ans = (len - 1) * len / 2;
			ans --;
			if(L[r] <= l) {
				ans -= pre[len - 1];
			}
			if(H(l, r) != T(n - r - 1, n - l - 1)) ans += len;
			cout << ans << '\n';
		}
	}
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	for(int i = 3; i <= 2e5; ++ i) pre[i] = pre[i - 1] + (i & 1) * i;
	for(int i = 1; i <= 2e5; ++ i) pw[i] = pw[i - 1] * B % P;
	int T = 1;
	cin >> T;
	while(T --) solve();
	return 0;
}
posted @ 2024-03-17 04:35  Lu_xZ  阅读(277)  评论(2编辑  收藏  举报