1. 程式人生 > 實用技巧 >CF #693 div3 做題記錄

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;
}