其他分享
首页 > 其他分享> > CF #693 div3 做题记录

CF #693 div3 做题记录

作者:互联网

主要是明天要考C语言上机,找一套CF div3拿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;
}

 

标签:p2,693,p1,int,ll,CF,else,tmp,div3
来源: https://www.cnblogs.com/CzxingcHen/p/14258920.html