Codeforces Round 932 (Div. 2) DE 题解

D. Exam in MAC

可以直接考虑容斥:

\(总数 - (x + y) 属于 s 的方案数 - (x - y) 属于 s 的方案数 + (x + y)且(x - y) 属于 s 的方案数。\)

对于两个减号,考虑枚举 \(s\) 的元素 \(p\),则会贡献 \(\frac{p}{2}+1\)\(x + y\) 的方案数) 和 \(c - p + 1\)\(x - y\) 的方案数) 的贡献。

对于最后一个加号,可以发现如果 \(x + y\)\(x - y\) 确定,则 \(x,y\) 就确定了,而有解条件是 \(x + y\)\(x - y\) 同奇偶,那么把 \(s\) 中的元素的奇数和偶数分别统计一下即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long

signed main() {
	ios::sync_with_stdio(false); cin.tie(0);
	int T; cin >> T;
	while (T--) {
		int n, c; cin >> n >> c;
		int s1 = 0, s2 = 0, c1 = 0, c2 = 0;
		for (int i = 1; i <= n; ++i) {
			int x; cin >> x;
			s1 += (x / 2) + 1; s2 += (c - x + 1); 
			if (x & 1) c1++; else c2++;
		} ++c;
		cout << c * (c - 1) / 2 + c - s1 - s2 + c1 * (c1 - 1) / 2 + c2 * (c2 - 1) / 2 + c1 + c2 << endl;
	} 
	return 0;
}

E. Distance Learning Courses in MAC

首先,如果 \(x_i,y_i\) 的最高位相同,那么其实对答案的影响是固定的,消去,不用考虑。

也就是说,我们现在只考虑 \(x_i,y_i\) 最高位不等的情况,记 \(z_i\) 表示选的数字。

容易想到从高到低位依次考虑枚举到 \(p\) 时如何填数,那么这时候我们记录 \(y_i\) 最高位为 \(p\) 的个数是 \(a\) 个,由上述描述,这 \(a\) 个区间 一定可以取到 \(2^p-1\)。再记当前已知对答案的影响是 \(b\) 个。

  1. \(a > 0 且 a + b \ge 2\),显然可以发现这种情况我们取一个 \(2^p-1\),再在剩下的 \(x + y - 1\) 个数中取一个 \(2^p\),就可以合成 \(2^{p+1}-1\),显然是达到了最优价,直接退出。

  2. \(a = 0 且 b \ge 1\),这种情况值的贡献是 \(2^p\),然后继续考虑 \(p - 1\) 的决策。

  3. \(a = 1 且 b = 0\),这种情况,显然 \(z_i\) 的最高位一定是是 \(2^p\),然后剩下的位数可以归结为一个子问题:我插入一个 \([0,y_i-2^p]\) 的数对,然后继续考虑 \(p - 1\) 的决策。

发现上述 3 中情况,只有情况 3 不好解决。

发现:这种情况只会改变 \(y_i\) 位数为 1 的那些位数的 \(a\) 值,其他的不会改变。所以说,如果我把 \(a\) 的定义改为:\(y_i\) 的最高位 \(\ge p\) 且第 \(p\) 位为 1 的个数,那第 3 中情况的贡献就和第 2 种情况的贡献一样,非常好解决了。

对于查询区间,我们可以用前缀和预处理 \(a\)\(b\) 的值,但是我赛时是将 \(a\) 分成了两个数组写,具体如下:

#include <bits/stdc++.h>
using namespace std;
#define int long long

int rd() {
	int x = 0, f = 1;
	char ch = getchar();
	while (!('0' <= ch && ch <= '9')) {
		if (ch == '-') f = -1; ch = getchar();
	}
	while ('0' <= ch && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();
	}
	return x * f;
}

void wr(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x >= 10) wr(x / 10); putchar(x % 10 + '0');
}

const int N = 2e5 + 10;

int x[N], y[N], L[N], R[N];

int f[N][35], g[N][35], h[N][35];

signed main() {
	ios::sync_with_stdio(false); cin.tie(0);
	int T; cin >> T;
	while (T--) {
		int n; cin >> n;
		for (int i = 1; i <= n; ++i) cin >> x[i] >> y[i];
		for (int i = 1; i <= n; ++i) {
			int fl = 1;
			for (int p = 30; p >= 0; --p) {
				f[i][p] = f[i - 1][p];
				g[i][p] = g[i - 1][p];
				h[i][p] = h[i - 1][p];
				if ((((x[i] >> p) & 1) == ((y[i] >> p) & 1)) && fl) {
					int v = (x[i] & (1 << p));
					if (v) f[i][p] ++;
				} else if (fl) {
					g[i][p]++; fl = 0;
	 			} else {
					if ((y[i] >> p) & 1) h[i][p]++;
				}
			}
		}
		int q; cin >> q;
		for (int i = 1; i <= q; ++i) cin >> L[i] >> R[i];
		for (int i = 1; i <= q; ++i) {
			int l = L[i], r = R[i]; 
			int sum = 0;
			for (int i = 29; i >= 0; --i) {
				int pf = f[r][i] - f[l - 1][i], pg = g[r][i] - g[l - 1][i], ph = h[r][i] - h[l - 1][i];
				if ((pg || ph) && (pf + pg + ph >= 2)) {
					sum += ((1 << (i + 1)) - 1); break;
				} else if (pf + pg + ph >= 1) sum += (1 << i);
			}
			cout << sum << " ";
		} cout << endl;
	}
	return 0;
}
posted @ 2024-03-06 01:14  wangzhongyuan  阅读(227)  评论(0编辑  收藏  举报