多校省选模拟07

多校省选模拟7

路过中丹

题意

给你一个字符串 \(s\),每次问 \(s[l:r]\) 能不能配得上丹,一个字符串配得上丹,当且仅当,你可以通过若干次行走,把这个子串的每个位置都遍历了。一次行走,就是把从一个点 \(i\) 到一个不一样的点 \(j\),使得经过的路径是个回文串。

题解

我们发现,如果存在一个,长度为三的回文串,那么肯定就行。这是显然的。

然后发现,肯定就是长度为偶数的回文串,能覆盖这个区间。

然后,发现,对于覆盖一个点来说,我们只要考虑以他为端点的最短偶回文串就可以了,不妨设长度为别为 \(L_i\)\(R_i\)

那么对于 \(l\in (i-L_i+1,i]\) 并且 \(r\in [i,i+R_i-1)\) 的情况,这个 \(i\) 肯定不能被覆盖。

然后发现,这是个矩阵加,单点查询,扫描线即可。

#include <bits/stdc++.h>
using std::pair;
using std::set;
using std::vector;
const int MAXN = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 998244353, G = 3, MOD2 = 1e9 + 7, G2 = 7;
template<typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
auto Mod = [] (int x) -> int {
	if (x < 0) {
		return x + MOD;
	}
	else if (x >= MOD) {
		return x - MOD;
	}
	else {
		return x;
	}
};
using std::cin;
using std::cout;
struct Line {
	int l, r, h, val;
} e[MAXN * 2];
pair<pair<int, int>, int> q[MAXN];
set<int> val;
vector<int> v[MAXN];
int N, Q, L[MAXN], R[MAXN], sum[MAXN], sc[MAXN], ANS[MAXN], H1[MAXN], H2[MAXN], pw[MAXN], H12[MAXN], H22[MAXN], pw2[MAXN];
char s[MAXN];
inline void add(int a, int b) {
	for (int i = a; i <= N; i += i & -i) {
		sc[i] += b;
	}
	return;
}
inline int qry(int pos) {
	int ret = 0;
	for (int i = pos; i; i -= i & -i) {
		ret += sc[i];
	}
	return ret;
}
int main() {
	freopen("pass.in", "r", stdin);
	freopen("pass.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);
	cin >> N >> s + 1 >> Q;
	pw[0] = 1;
	pw2[0] = 1;
	for (int i = 1; i <= N; ++i) {
		L[i] = R[i] = INF;
		H12[i] = ((long long) H12[i - 1] * G2 + s[i]) % MOD2;
		H1[i] = ((long long) H1[i - 1] * G + s[i]) % MOD;
		pw[i] = (long long) pw[i - 1] * G % MOD;
		pw2[i] = (long long) pw2[i - 1] * G2 % MOD2;
	}
	for (int i = N; i; --i) {
		H22[i] = ((long long) H22[i + 1] * G2 + s[i]) % MOD2;
		H2[i] = ((long long) H2[i + 1] * G + s[i]) % MOD;
	}
	auto h1 = [&] (int l, int r) -> int {
		return Mod(H1[r] - (long long) H1[l - 1] * pw[r - l + 1] % MOD);
	};
	auto h2 = [&] (int l, int r) -> int {
		return Mod(H2[l] - (long long) H2[r + 1] * pw[r - l + 1] % MOD);
	};
	auto h12 = [&] (int l, int r) -> int {
		return (H12[r] - (long long) H12[l - 1] * pw2[r - l + 1] % MOD2 + MOD2) % MOD2;
	};
	auto h22 = [&] (int l, int r) -> int {
		return (H22[l] - (long long) H22[r + 1] * pw2[r - l + 1] % MOD2 + MOD2) % MOD2;
	};
	for (int i = 1; i < N; ++i) {
		int l = 1, r = min(i, N - i), ret = -1;
		while (l <= r) {
			int mid = (l + r) / 2;
			if (h1(i - mid + 1, i + mid) == h2(i - mid + 1, i + mid) && h12(i - mid + 1, i + mid) == h22(i - mid + 1, i + mid)) {
				ret = mid;
				l = mid + 1;
			}
			else {
				r = mid - 1;
			}
		}
		if (~ret) {
			v[i - ret + 1].push_back(i);
			v[i + ret + 1].push_back(-i);
		}
	}
	for (int i = 1; i <= N; ++i) {
		for (auto &j: v[i]) {
			if (j < 0) {
				val.erase(-j);
			}
			else {
				val.insert(j);
			}
		}
		auto it = val.lower_bound(i);
		if (it != val.end()) {
			R[i] = 2 * (*it - i + 1);
		}
		if (it != val.begin()) {
			--it;
			L[i] = 2 * (i - *it);
		}
	}
	for (int i = 2; i < N; ++i) {
		sum[i] = sum[i - 1] + (s[i - 1] == s[i + 1]);
	}
	for (int i = 1; i <= N; ++i) {
		int ql = max(1, i - L[i] + 2), qr = min(i + R[i] - 2, N);
		e[2 * i - 1] = {i, qr, ql, 1};
		e[2 * i] = {i, qr, i + 1, -1};
	}
	std::sort(e + 1, e + 1 + 2 * N, [&] (const Line &a, const Line &b) {
		return a.h < b.h;
	});
	for (int i = 1; i <= Q; ++i) {
		cin >> q[i].first.first >> q[i].first.second;
		q[i].second = i;
	}
	std::sort(q + 1, q + 1 + Q);
	for (int i = 1, j = 1; i <= Q; ++i) {
		while (j <= 2 * N && e[j].h <= q[i].first.first) {
			add(e[j].l, e[j].val);
			add(e[j].r + 1, -e[j].val);
			++j;
		}
		if (q[i].first.first != q[i].first.second) {
			if (sum[q[i].first.second - 1] - sum[q[i].first.first]) {
				ANS[q[i].second] = 1;
			}
			else {
				ANS[q[i].second] = !qry(q[i].first.second);
			}
		}
	}
	// for (int i = 1; i <= N; ++i) {
	// 	cout << L[i] << ' ' << R[i] << '\n';
	// }
	for (int i = 1; i <= Q; ++i) {
		cout << ANS[i];
	}
	return 0;
}

膜拜大丹

题意

\(n\)\(A\) 类点, \(m\)\(B\) 类点,然后他们分别有自己的属性 \(a_i\) 或者 \(b_i\),满足 \(A\) 类点向着 \(1\sim a_i\)\(B\) 类点连边,\(B\) 类点向着 \(1\sim b_i\)\(A\) 类点连边,你在这个图上,然后要每次选出来一个环,然后每个点选的次数有个上限,问你最多能选出来多少环。

题解

我们首先可以发现,一个膜拜路径,其实是个二元环就够了,因为如果大于二元环的话,不妨设是 \(A1\rightarrow B1\rightarrow A2\rightarrow B2\rightarrow A1\)

不妨设 \(A1<A2\),那么应该有 \(A1<A2<b[B1]\),那么肯定就是可以形成一个 \(A1,B1\) 的二元环了。

那么既然是二元环,那就类似于二分图匹配,我们考虑跑个网络流。这就有不少分了。

接下来,考虑,模拟最大流即可。

思考一下,发现,我们如果把这点都映射到一个二维平面直角坐标系里的话,\(A\) 里边的点,映射为 \((i,a_i)\),然后 \(B\) 里边的点映射为 \((b_i,i)\),然后考虑从 \(A\) 部的从右向左地开始做,每次呢,总是选出来合法的 \(y\) 最大的 \(B\) 类点。

使用这种方法,在考虑怎么去进行增广。发现,根本不可能有对于之前的操作的退流,然后直接跑就完了。

#include <bits/stdc++.h>
using std::pair;
using std::set;
using std::vector;
const int MAXN = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 998244353, G = 3, MOD2 = 1e9 + 7, G2 = 7;
template<typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
auto Mod = [] (int x) -> int {
	if (x < 0) {
		return x + MOD;
	}
	else if (x >= MOD) {
		return x - MOD;
	}
	else {
		return x;
	}
};
using std::cin;
using std::cout;
struct Line {
	int l, r, h, val;
} e[MAXN * 2];
pair<pair<int, int>, int> q[MAXN];
set<int> val;
vector<int> v[MAXN];
int N, Q, L[MAXN], R[MAXN], sum[MAXN], sc[MAXN], ANS[MAXN], H1[MAXN], H2[MAXN], pw[MAXN], H12[MAXN], H22[MAXN], pw2[MAXN];
char s[MAXN];
inline void add(int a, int b) {
	for (int i = a; i <= N; i += i & -i) {
		sc[i] += b;
	}
	return;
}
inline int qry(int pos) {
	int ret = 0;
	for (int i = pos; i; i -= i & -i) {
		ret += sc[i];
	}
	return ret;
}
int main() {
	freopen("pass.in", "r", stdin);
	freopen("pass.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);
	cin >> N >> s + 1 >> Q;
	pw[0] = 1;
	pw2[0] = 1;
	for (int i = 1; i <= N; ++i) {
		L[i] = R[i] = INF;
		H12[i] = ((long long) H12[i - 1] * G2 + s[i]) % MOD2;
		H1[i] = ((long long) H1[i - 1] * G + s[i]) % MOD;
		pw[i] = (long long) pw[i - 1] * G % MOD;
		pw2[i] = (long long) pw2[i - 1] * G2 % MOD2;
	}
	for (int i = N; i; --i) {
		H22[i] = ((long long) H22[i + 1] * G2 + s[i]) % MOD2;
		H2[i] = ((long long) H2[i + 1] * G + s[i]) % MOD;
	}
	auto h1 = [&] (int l, int r) -> int {
		return Mod(H1[r] - (long long) H1[l - 1] * pw[r - l + 1] % MOD);
	};
	auto h2 = [&] (int l, int r) -> int {
		return Mod(H2[l] - (long long) H2[r + 1] * pw[r - l + 1] % MOD);
	};
	auto h12 = [&] (int l, int r) -> int {
		return (H12[r] - (long long) H12[l - 1] * pw2[r - l + 1] % MOD2 + MOD2) % MOD2;
	};
	auto h22 = [&] (int l, int r) -> int {
		return (H22[l] - (long long) H22[r + 1] * pw2[r - l + 1] % MOD2 + MOD2) % MOD2;
	};
	for (int i = 1; i < N; ++i) {
		int l = 1, r = min(i, N - i), ret = -1;
		while (l <= r) {
			int mid = (l + r) / 2;
			if (h1(i - mid + 1, i + mid) == h2(i - mid + 1, i + mid) && h12(i - mid + 1, i + mid) == h22(i - mid + 1, i + mid)) {
				ret = mid;
				l = mid + 1;
			}
			else {
				r = mid - 1;
			}
		}
		if (~ret) {
			v[i - ret + 1].push_back(i);
			v[i + ret + 1].push_back(-i);
		}
	}
	for (int i = 1; i <= N; ++i) {
		for (auto &j: v[i]) {
			if (j < 0) {
				val.erase(-j);
			}
			else {
				val.insert(j);
			}
		}
		auto it = val.lower_bound(i);
		if (it != val.end()) {
			R[i] = 2 * (*it - i + 1);
		}
		if (it != val.begin()) {
			--it;
			L[i] = 2 * (i - *it);
		}
	}
	for (int i = 2; i < N; ++i) {
		sum[i] = sum[i - 1] + (s[i - 1] == s[i + 1]);
	}
	for (int i = 1; i <= N; ++i) {
		int ql = max(1, i - L[i] + 2), qr = min(i + R[i] - 2, N);
		e[2 * i - 1] = {i, qr, ql, 1};
		e[2 * i] = {i, qr, i + 1, -1};
	}
	std::sort(e + 1, e + 1 + 2 * N, [&] (const Line &a, const Line &b) {
		return a.h < b.h;
	});
	for (int i = 1; i <= Q; ++i) {
		cin >> q[i].first.first >> q[i].first.second;
		q[i].second = i;
	}
	std::sort(q + 1, q + 1 + Q);
	for (int i = 1, j = 1; i <= Q; ++i) {
		while (j <= 2 * N && e[j].h <= q[i].first.first) {
			add(e[j].l, e[j].val);
			add(e[j].r + 1, -e[j].val);
			++j;
		}
		if (q[i].first.first != q[i].first.second) {
			if (sum[q[i].first.second - 1] - sum[q[i].first.first]) {
				ANS[q[i].second] = 1;
			}
			else {
				ANS[q[i].second] = !qry(q[i].first.second);
			}
		}
	}
	// for (int i = 1; i <= N; ++i) {
	// 	cout << L[i] << ' ' << R[i] << '\n';
	// }
	for (int i = 1; i <= Q; ++i) {
		cout << ANS[i];
	}
	return 0;
}
posted @ 2022-01-23 19:30  siriehn_nx  阅读(57)  评论(0编辑  收藏  举报