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\)。再記當前已知對答案的影響是 \(y\) 個。
-
\(a > 0 且 a + b \ge 2\),顯然可以發現這種情況我們取一個 \(2^p-1\),再在剩下的 \(x + y - 1\) 個數中取一個 \(2^p\),就可以合成 \(2^{p+1}-1\),顯然是達到了最優價,直接退出。
-
\(a = 0 且 a \ge 1\),這種情況值可能貢獻 \(2^p\)。
-
\(a = 1 且 a = 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;
}