Deltix Round, Summer 2021 Div1 + Div2 A~E
比賽連結:Here
1556A. A Variety of Operations
注意到2, 3操作不改變總和,1操作使得總和加上了一個偶數,故直接判斷總和是否為偶數即可。如果和為偶數,只要判斷c和d是否相等即可。注意0要判一下
【AC Code】
const int N = 1e5 + 7; int n, m, k, tot, a[N]; int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int _; for (cin >> _; _--;) { int c, d; cin >> c >> d; if (c == 0 && d == 0) { puts("0"); continue; } if ((c + d) % 2 == 0) { if (c == d ) { puts("1"); } else puts("2"); } else puts("-1"); } }
1566B. Take Your Places!
題意:
給一個有 \(n\) 個數字的陣列,可以交換相鄰的數字,求最小交換次數使得相鄰的數奇偶性不相同。
思路:
先判一下奇數和偶數的個數,在按順序分配位置就行。如果奇數和偶數個數相等,還得列舉奇數先放還是偶數先放。注意開 ll
。
【AC Code】
int main() { cin.tie(nullptr)->sync_with_stdio(false); int _; for (cin >> _; _--;) { int n; cin >> n; vector<int>a(n); for (int &x : a) { cin >> x; x &= 1; } ll ans = LLONG_MAX; for (int j = 0; j < 2; ++j) { vector<int>b(n); for (int i = 0; i < n; ++i) b[i] = (i & 1) == j; vector<int>la, lb; for (int i = 0; i < n; ++i) { if (a[i]) la.push_back(i); if (b[i]) lb.push_back(i); } if (la.size() != lb.size()) continue; ll op = 0; for (int i = 0; i < la.size(); ++i) op += abs(la[i] - lb[i]); ans = min(ans, op); } cout << (ans >= LLONG_MAX ? -1 : ans) << "\n"; } }
1566C. Compressed Bracket Sequence
莫名其妙地ac了,不是很懂。
首先列舉左端點 \(l\) 和右端點 \(r\) ,用函式 \(check(l,r)\) 統計這兩個端點的貢獻(在 \(l\) 處開始,$ r$ 處結束的合法括號序列的數量)。假設每一個左括號為 \(1\),右括號為 \(-1\) ,對序列求個字首和,方便判斷是否合法。
所有的從 \(l\) 開始,\(r\) 結束的合法括號序列,不一定用了\(l\)和\(r\)中的每一個左右括號。
首先計算 \(d=sum[r]-sum[l-1]\) ,以得出左右兩邊是否有多餘的括號,我們要捨去。之後再列舉\(l+1\)
之後保險起見,還得和左邊能貢獻的左括號數量,右邊能貢獻的右括號數量取 \(\min\),注意此時也要把$ d$ 的偏差加上去,具體見程式碼。
【AC Code】
const int N = 1e5 + 7;
int n, m, k;
ll tot, c[N], ans, sum[N];
ll check(int l, int r) {
ll d = sum[r] - sum[l - 1], mx = 99999999999999999ll;
for (int i = l + 1; i < r; i += 2) {
if (d <= 0)
mx = min(mx, sum[i] - sum[l - 1]);
if (d > 0)
mx = min(mx, sum[i] - d - sum[l - 1]);
}
if (mx < 0) return 0;
//if (mx == 0) return 1;
if (d == 0) return min(c[l], min(mx + 1ll, -c[r]));
if (d < 0) return min(c[l], min(mx + 1ll, -c[r] + d));
if (d > 0) return min(c[l] - d, min(mx + 1ll, -c[r]));
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> c[i];
if (i % 2 == 0) c[i] = -c[i];
sum[i] = sum[i - 1] + c[i];
}
for (int l = 1; l <= n; l += 2) {
for (int r = l + 1; r <= n; r += 2) {
ans += check(l, r);
}
}
cout << ans;
}
1566D. Take a Guess
第一次做互動題,要頻繁清空流感覺有點麻煩
$ a+b=a & b+a \mid b$ ,用 \(a+b, a+c, b+c\) 可以求出 $ a b c $ ,已知 $ a$ 和 \(a \& b+a \mid b\) 可以求 b , 這樣直接求出所有的 $ a[i]$ 就行。
【AC Code】
注意每一行輸出之後要立刻 fflush(stdout);
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
typedef pair<int, int> pii;
#define mk make_pair
const int maxn = 1e4 + 7;
int rd() {
int s = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
return s * f;
}
int n, m, k, tot;
ll a[maxn];
ll getPlus(int i, int j) {
printf("or %d %d\n", i, j);
fflush(stdout);
ll orij = rd();
printf("and %d %d\n", i, j);
fflush(stdout);
ll andij = rd();
return orij + andij;
}
void get(int i, int j, int k) {
ll pij = getPlus(i, j);
ll pjk = getPlus(j, k);
ll pik = getPlus(i, k);
a[i] = (pij - pjk + pik) / 2ll;
a[j] = (pjk - pik + pij) / 2ll;
a[k] = (pik - pij + pjk) / 2ll;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
n = rd(); k = rd();
for (int i = 1; i <= n; i += 3) {
if (i + 2 > n) break;
get(i, i + 1, i + 2);
}
if (n % 3 == 1) {
ll p1 = getPlus(1, n);
a[n] = p1 - a[1];
}
if (n % 3 == 2) {
ll p1 = getPlus(1, n - 1);
a[n - 1] = p1 - a[1];
ll p2 = getPlus(1, n);
a[n] = p2 - a[1];
}
sort(a + 1, a + n + 1);
printf("finish %lld\n", a[k]);
}
1556E. Equilibrium
給出倆個長為 \(n\) 的整數序列 \(a\) 和 \(b\) ,以及一些詢問 $(1, \mathrm{r}) \(. 對於每個\) (l, r) \(, 回答最少要執行多少次操作,使得
\) \mathrm{a}[1 \ldots \mathrm{r}]=\mathrm{b}[1 \ldots \mathrm{r}] $, 或是判斷無解。
每次操作為選取偶數個下標 \(p o s_{i}\) , 滿足 $ l \leq p o s_{1}<p o s_{2}<\cdots<p o s_{k} \leq r $, 然後讓 \(a\) 中下標為
$\operatorname{pos}{1}, \operatorname{pos}{3}, p o s_{5}, \cdots, p o s_{k}-1 $ 的數 \(+1\) , 讓 \(b\) 中下標為 $p o s_{2}, p o s_{4}, \operatorname{pos}{6}, \cdots, p o s{k} $ 的位置的數 $+1 $.
每次詢問是互相獨立的。
sol:這裡參考了高Rank大佬們的思路
【AC Code】
const int maxn = 1e5 + 7;
#define ll long long
int n, m, k, tot, a[maxn], q;
ll sum[maxn];
ll stmx[22][maxn], stmi[22][maxn];
int rd() {
int s = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
return s * f;
}
ll querymi(int l, int r) {
int len = r - l + 1, len2;
for (len2 = 0; (1 << (len2 + 1)) < len; len2++);
return min(stmi[len2][l], stmi[len2][r - (1 << len2) + 1]);
}
ll querymx(int l, int r) {
int len = r - l + 1, len2;
for (len2 = 0; (1 << (len2 + 1)) < len; len2++);
return max(stmx[len2][l], stmx[len2][r - (1 << len2) + 1]);
}
int main() {
n = rd();
q = rd();
//printf("%d %d\n", n, q);
for (int i = 1; i <= n; i++)
a[i] = rd();
for (int i = 1; i <= n; i++) {
a[i] -= rd();
sum[i] = sum[i - 1] + a[i];
stmx[0][i] = stmi[0][i] = sum[i];
}
//q = rd();
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= n - (1 << j) + 1; i++)
stmi[j][i] = 100000000000001ll, stmx[j][i] = -100000000000001ll;
for (int i = 1; i <= 20; i++) {
for (int j = 1; j <= n - (1 << i) + 1; j++) {
stmi[i][j] = min(stmi[i - 1][j], stmi[i - 1][j + (1 << (i - 1))]);
stmx[i][j] = max(stmx[i - 1][j], stmx[i - 1][j + (1 << (i - 1))]);
}
}
while (q--) {
int l = rd();
int r = rd();
//printf("l == %d r == %d qmx == %lld qmi == %lld\n", l, r, querymx(l, r)-sum[l-1], querymi(l, r)-sum[l-1]);
if (sum[r] - sum[l - 1] != 0 || querymx(l, r) > sum[l - 1]) {
puts("-1");
continue;
} else {
printf("%lld\n", -(querymi(l, r) - sum[l - 1]));
}
}
return 0;
}
The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。