CF #693 div3 做題記錄
主要是明天要考C語言上機,找一套CFdiv3拿C語言寫一遍。
A
給一張$w*h$的紙,如果$w$(長)是偶數,那麼就可以沿著剪開,變成兩張$\frac{w}{2}*h$的紙,寬同理,問最後能不能得到(可以超過)$n$張紙。
剪到不能減,剪一次多一倍,就是看pow(2, $w$和$h$的因子$2$的個數)是不是超過$n$。
#include <stdio.h> typedef long long ll; int T, w, h; ll n; int main() { #ifndef ONLINE_JUDGE freopen("sample.in", "r", stdin);#endif for (scanf("%d", &T); T--; ) { scanf("%d%d%lld", &w, &h, &n); ll cnt = 1; for (; !(w & 1); w >>= 1, cnt <<= 1); for (; !(h & 1); h >>= 1, cnt <<= 1); if (cnt >= n) puts("YES"); else puts("NO"); } return 0; }
B
給了一堆糖,要麼重量為1,要麼重量為2,現在想要平均分成兩堆(不能把2拆成1+1),問能不能做到。
總重量是確定的,而且必須是個偶數,然後就是考慮能否湊出總重量的一半。
發現1比2好用,所以先儘可能多用2,剩下用1補齊。
upd:貌似這個做法很鬼畜啊,只要按照奇偶討論一下就好了。
#include <stdio.h> #define N 105 int T, n, a[N]; int min(int x, int y) { return x < y ? x : y; } int main() { #ifndef ONLINE_JUDGE freopen("sample.in", "r", stdin); #endif for (scanf("%d", &T); T--; ) { scanf("%d", &n); int sum = 0, cnt2 = 0; for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); sum += a[i]; if (a[i] == 2) ++cnt2; } if (sum & 1) puts("NO"); else { sum >>= 1; int k = sum / 2; if (sum - min(cnt2, k) * 2 <= n - cnt2) puts("YES"); else puts("NO"); } } return 0; }
C
給一個數組$a[]$,每次可以從$i$跳到$i+a[i]$,停在$i$上可以獲得$a_i$的價值,直到超過$n$,最大化價值。
從後往前遞推。
#include <stdio.h> typedef long long ll; #define N 200005 int T, n; ll a[N], f[N]; ll max(ll x, ll y) { return x > y ? x : y; } int main() { #ifndef ONLINE_JUDGE freopen("sample.in", "r", stdin); #endif for (scanf("%d", &T); T--; ) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); ll ans = 0; for (int i = n; i >= 1; i--) { if (i + a[i] > n) f[i] = a[i]; else f[i] = f[i + a[i]] + a[i]; ans = max(ans, f[i]); } printf("%lld\n", ans); } return 0; }
D
alice和bob玩遊戲,給了一個長度為$n$的陣列,每次可以選擇移除一個元素,alice先手。若alice移除偶數,則alice得到價值為這個偶數的分數,若bob移除奇數則bob得到價值為這個奇數的分數,陣列空的時候比兩個人的得分誰高。如果兩個人都足夠聰明,判斷勝負。
alice要移除一個偶數,一定是移除最大的偶數;若她要移除一個奇數,也一定是當前最大的奇數。進一步,發現不論是alice還是bob都一定會移除當前最大的數,如果當前分差(alice - bob)為$x$,最大的奇數為$y$,最大的偶數為$z$,假設alice拿走$z$,則分差就可以變為$x+z-y$,當$y > z$時不優,這時alice拿走$y$,可以使損失最小。
腦抽了,寫了個分類討論。
#include <stdio.h> typedef long long ll; #define N 200005 int T, n; ll a[N], b[N], c[N], tmp[N]; void sort(ll *arr, int l, int r) { if (l > r) return; if (l == r) return; int mid = (l + r) >> 1; sort(arr, l, mid), sort(arr, mid + 1, r); for (int i = l; i <= r; i++) tmp[i] = arr[i]; for (int p = l, p1 = l, p2 = mid + 1; p1 <= mid || p2 <= r; ++p) { if (p1 > mid) arr[p] = tmp[p2], ++p2; else if (p2 > r) arr[p] = tmp[p1], ++p1; else { if (tmp[p1] < tmp[p2]) arr[p] = tmp[p1], ++p1; else arr[p] = tmp[p2], ++p2; } } } int main() { #ifndef ONLINE_JUDGE freopen("sample.in", "r", stdin); #endif for (scanf("%d", &T); T--; ) { scanf("%d", &n); int cnt1 = 0, cnt2 = 0; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); if (a[i] & 1) c[++cnt2] = a[i]; else b[++cnt1] = a[i]; } sort(b, 1, cnt1); sort(c, 1, cnt2); ll alice = 0, bob = 0; for (int i = 1, p1 = cnt1, p2 = cnt2; i <= n; i++) { if (i & 1) { if (!p1) --p2; else if (!p2) alice += b[p1], --p1; else { if (b[p1] > c[p2]) alice += b[p1], --p1; else --p2; } } else { if (!p2) --p1; else if (!p1) bob += c[p2], --p2; else { if (c[p2] > b[p1]) bob += c[p2], --p2; else --p1; } } } if (alice > bob) puts("Alice"); else if (alice < bob) puts("Bob"); else puts("Tie"); } return 0; }
E
給了$n$對二元組$(w, h)$,定義$j$在$i$前面為$(w_j < w_i & h_j < h_i) | (w_j < h_i & h_j < w_i)$,求每一個元素前面的任意一個元素編號,若沒有,輸出$-1$。
首先通過交換可以使$h_i \leq w_i$,那麼元素$i$在元素$j$前面的充要條件變成$h_j < h_i & w_j < w_i$,二維偏序。
注意某個量相同的情況。
#include <stdio.h> typedef long long ll; #define N 200005 int T, n, ans[N]; struct Node { int w, h, id; } a[N], tmp[N]; void sort(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; sort(l, mid), sort(mid + 1, r); for (int i = l; i <= r; i++) tmp[i] = a[i]; for (int p = l, p1 = l, p2 = mid + 1; p1 <= mid || p2 <= r; ++p) { if (p1 > mid) a[p] = tmp[p2], ++p2; else if (p2 > r) a[p] = tmp[p1], ++p1; else { if (tmp[p1].h < tmp[p2].h) a[p] = tmp[p1], ++p1; else a[p] = tmp[p2], ++p2; } } } int main() { #ifndef ONLINE_JUDGE freopen("sample.in", "r", stdin); #endif for (scanf("%d", &T); T--; ) { scanf("%d", &n); // printf("%d\n", n); for (int i = 1; i <= n; i++) { scanf("%d%d", &a[i].h, &a[i].w); if (a[i].h > a[i].w) { int inttmp = a[i].h; a[i].h = a[i].w; a[i].w = inttmp; } a[i].id = i; ans[i] = -1; } // for (int i = 1; i <= n; i++) // printf("%d %d %d\n", a[i].h, a[i].w, a[i].id); sort(1, n); // for (int i = 1; i <= n; i++) // printf("%d %d %d\n", a[i].h, a[i].w, a[i].id); a[0].h = a[1].h; for (int now = 0, p = 1, i = 1; i <= n; i++) { if (a[i].h != a[i - 1].h) { for (; p < i; p++) if (a[p].w < a[now].w || now == 0) now = p; } if (now != 0 && a[now].w < a[i].w) ans[a[i].id] = a[now].id; } for (int i = 1; i <= n; i++) printf("%d%c", ans[i], " \n"[i == n]); } return 0; }
F
先咕著
G
給一張有向圖,設以$1$為源點的單源最短路為$d[]$,可以順著$d$變大的道路走無數次,但是隻能順著$\leq d_i$的道路走最多一次,問從每一個點出發能走到的離$1$的最近距離。
分層圖,一個點$x$拆成$x_0$和$x_1$表示走到$x$有/沒有使用過$\leq d_i$的機會,發現這樣子的圖一定是一個DAG,記搜即可。
反證法:上下兩層一樣,若上下兩層中有環,繞著環走一圈相當於$d_x > d_x$,矛盾,然後在兩層之間走的時候只能上不能下,所以整張圖沒有環。
不想用C。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef double db; typedef pair <int, int> pin; const int N = 2e5 + 5; const int inf = 0x3f3f3f3f; const ll P = 998244353LL; int T, n, m, tot, head[N << 1], dis[N], ans[N], f[N]; bool vis[N << 1]; struct Pathway { int x, y; } pat[N]; struct Edge { int to, nxt; } e[N << 1]; inline void add(int from, int to) { e[++tot].to = to; e[tot].nxt = head[from]; head[from] = tot; } template <typename T> inline void read(T &X) { char ch = 0; T op = 1; for (X = 0; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') op = -1; for (; ch >= '0' && ch <= '9'; ch = getchar()) X = (X * 10) + ch - '0'; X *= op; } priority_queue <pin> q; void dij(int s) { q.push(pin(dis[s] = 0, s)); for (; !q.empty(); ) { int x = q.top().second; q.pop(); if (vis[x]) continue; vis[x] = 1; for (int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if (dis[y] > dis[x] + 1) { dis[y] = dis[x] + 1; q.push(pin(-dis[y], y)); } } } } int solve(int x) { if (x == 1) return f[x] = 0; if (f[x] != inf) return f[x]; int res = (x <= n ? dis[x] : dis[x - n]); for (int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; res = min(res, solve(y)); } return f[x] = res; } int main() { #ifndef ONLINE_JUDGE freopen("sample.in", "r", stdin); #endif for (read(T); T--; ) { read(n), read(m); tot = 0; for (int i = 1; i <= n; i++) dis[i] = inf, vis[i] = 0, head[i] = 0; for (int x, y, i = 1; i <= m; i++) { read(x), read(y); add(x, y); pat[i].x = x, pat[i].y = y; } dij(1); // for (int i = 1; i <= n; i++) printf("%d%c", dis[i], " \n"[i == n]); tot = 0; for (int i = 1; i <= n + n; i++) head[i] = 0, vis[i] = 0, f[i] = inf; for (int i = 1; i <= m; i++) { int x = pat[i].x, y = pat[i].y; if (dis[x] < dis[y]) add(x, y), add(x + n, y + n); else add(x, y + n); } for (int i = 1; i <= n; i++) printf("%d%c", solve(i), " \n"[i == n]); } return 0; }