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
", 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);
        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
", a[i].h, a[i].w, a[i].id);

        sort(1, n);

        // for (int i = 1; i <= n; i++)
        //     printf("%d %d %d
", 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], " 
"[i == n]);
    }
    return 0;
}

F

给了一个$2 imes n$的网格,有若干个格子是不能被覆盖的,判断能否用$1 imes 2$的格子覆盖。

除去空地,一个位置最多有三种状态(上面有,下面有,全都有),发现后面的覆盖之后的状态可以由前面的障碍物的状态唯一确定,所以只要从前往后枚举所有的格子通过分类讨论枚举检查的过程就可以了。

把$0$和$n+1$都记为“全都有”加入数组。

比较的时候会修改原数组,记得直接continue掉。

#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 ll P = 998244353LL;

int T, n, m, s[N];
map <int, int> a;
vector <int> vec;

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

int main() {
#ifndef ONLINE_JUDGE
    freopen("sample.in", "r", stdin);
#endif

    for (read(T); T--; ) {
        read(n), read(m);
        a.clear();
        a[0] = 3, a[n + 1] = 3;
        for (int r, c, i = 1; i <= m; i++) {
            read(r), read(c);
            a[c] += 1 << (r - 1);
        }
        vec.clear();
        for (map <int, int>::iterator it = a.begin(); it != a.end(); ++it) {
            vec.push_back(it -> first);
            s[vec.size() - 1] = it -> second;
        }

        // for (int i = 0; i < vec.size(); i++)
        //     printf("%d%c", vec[i], " 
"[i == vec.size() - 1]);
        // for (int i = 0; i < vec.size(); i++)
        //     printf("%d%c", s[i], " 
"[i == vec.size() - 1]);

        bool ok = 1;
        for (int i = 1; i < vec.size(); i++) {
            if (s[i] == 1) {
                if (s[i - 1] == 3) continue;
                else if (s[i - 1] == 1) {
                    if ((vec[i] - vec[i - 1]) & 1) {
                        s[i] = 3;
                        continue;
                    } else {
                        ok = 0;
                        break;
                    }
                } else {
                    if (!((vec[i] - vec[i - 1]) & 1)) {
                        s[i] = 3;
                        continue;
                    } else {
                        ok = 0;
                        break;
                    }
                }
            } else if (s[i] == 2) {
                if (s[i - 1] == 3) continue;
                else if (s[i - 1] == 2) {
                    if ((vec[i] - vec[i - 1]) & 1) {
                        s[i] = 3;
                        continue;
                    } else {
                        ok = 0;
                        break;
                    }
                } else {
                    if (!((vec[i] - vec[i - 1]) & 1)) {
                        s[i] = 3;
                        continue;
                    } else {
                        ok = 0;
                        break;
                    }
                }
            } else {
                if (s[i - 1] == 3) continue;
                else {
                    ok = 0;
                    break;
                }
            }
        }
        puts(ok ? "Yes" : "No");
    }
    return 0;
}

不想用C语言。

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], " 
"[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), " 
"[i == n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/CzxingcHen/p/14258920.html