qoj1706 Infinite Parenthesis Sequence

发布时间 2023-11-09 09:43:44作者: Smallbasic

找规律害人害己。

\(f(k,x)\) 表示操作 \(k\) 次之后第 \(x\) 个左括号的位置,知道 \(f(k,x)\) 之后可以简单二分出答案。

首先考虑 \(f\) 的递推式,左括号的位置改变有两种情况。((->(X 和 ()->)(,对应过来就是 \(f(k+1,x)=\min(f(k,x)+1,f(k,x+1)-1)\),考虑用 \(f(0,y)\) 表示出 \(f(k,x)\),有:

\[f(k,x)=\min_{x\le y\le x+k} f(0,y)+k-2(y-x) \]

\(m\) 为左括号个数,如果 \(k\) 较小,则直接处理出 \(f(0,[0,2m))\),每次 rmq 找最小值即可。

考虑 \(k\) 比较大的情况,跨掉一个串之后的 \(f\) 变化是很有规律的。容易发现 \(f(0,j+m)=f(0,j)+n\),而贡献到 \(f(k,x)\) 时他们的贡献会相差 \(2m\),所以我们对于 \(n-2m\) 分类讨论,如果 \(n-2m>0\),则尽量选靠左的 \(m\) 个,否则尽量选靠右的 \(m\) 个,依然可以通过简单 rmq 解决。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5;

typedef long long ll;

inline int read() {
	register int s = 0, f = 1; register char ch = getchar();
	while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
	while (isdigit(ch)) s = (s * 10) + (ch & 15), ch = getchar();
	return s * f;
}

inline void otp(int x) {
	(x >= 10) ? otp(x / 10), putchar((x % 10) ^ 48) : putchar(x ^ 48);
}

int n, q, mn[N << 1][20], top = 0;
char ch[N];

inline int f(int k, int x) {
	int l, r;
	if (2 * top <= n) l = x, r = min(l + k, l + top - 1);
	else r = x + k, l = max(x, r - top + 1);
	int p = (l % top + top) % top + 1;
	int t = __lg(r - l + 1), B = (l >= 0) ? l / top : (l + 1) / top - 1;
	return min(mn[p][t], mn[p + (r - l + 1) - (1 << t)][t]) + (n - 2 * top) * B + k + 2 * x;
}

inline int query(int k, int x) {
	int l = -1e9, r = 1e9, mid, res;
	while (l <= r) {
		mid = l + r >> 1;
		if (f(k, mid) <= x) l = (res = mid) + 1;
		else r = mid - 1;
	} return res;
}

int main() {
	int T; T = read();
	while (T--) {
		scanf("%s", ch); q = read();
		n = strlen(ch);
		top = 0;
		for (int i = 0; i < n; ++i)
			if (ch[i] == '(') mn[++top][0] = i;
		for (int i = top + 1; i <= top * 2; ++i) mn[i][0] = mn[i - top][0] + n;
		for (int i = 1; i <= top * 2; ++i) mn[i][0] -= 2 * (i - 1);
		for (int i = 1; i < 20; ++i)
			for (int j = 1; j + (1 << i) <= top * 2; ++j)
				mn[j][i] = min(mn[j][i - 1], mn[j + (1 << i - 1)][i - 1]);
		while (q--) {
			int k, l, r; k = read(); l = read(); r = read();
			otp(top ? query(k, r) - query(k, l - 1) : 0);
			putchar('\n');
		}
	} return 0;
}