Red Huang

Red Huang

Codeforces ラウンド #407 (Div. 2)

Codeforces Round #407 (Div. 2)#

A. アナスタシアと小石#

貪欲に取れば大丈夫です
ルールは各ポケットには 1 種類の小石しか入れられず、すべての石を取り切る必要があります
つまり、できるだけ詰め込むだけで終わりです
要するに貪欲法です

#include <cstdio>
#include <cstdlib>

using namespace std;

/*
 * 20/4=5..0
 * 13/4=3..1
 */
int main() {
//    freopen("input.txt", "r", stdin);
    int n, k;
    int a[100005];
    int cnt = 0;
    scanf("%d %d\n", &n, &k);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < n;) {
        if (a[i] <= 0) {
            i++;
            continue;
        }
        if (a[i] >= (k + k)) {
            cnt += a[i] / (k + k);
            a[i] %= (k + k);
        } else if (a[i] > k) {
            a[i]=0;
            cnt++;
        }else {
            cnt++;
            a[i]-=k;
            a[i+1]-=k;
        }
    }
    printf("%d\n", cnt);

} 

B. マーシャと幾何学的抑圧#

簡単に言えば unordered_set と暴力的なシミュレーションを使えば解決できます
int が足りないことを忘れないでください

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <unordered_set>

using namespace std;

unordered_set<long long> s;

int main() {
//    freopen("input.txt", "r", stdin);
    long long b, q, l, m;
    scanf("%I64d%I64d%I64d%I64d", &b, &q, &l, &m);
    for (int i = 0; i < m; i++) {
        long long tmp;
        scanf("%I64d", &tmp);
        s.insert(tmp);
    }
    if (abs(b) > l) {
        printf("0\n");
        return 0;
    }
    if (b == 0) {
        if (s.find(0) != s.end()) {
            printf("0\n");
        } else {
            printf("inf\n");
        }
        return 0;
    }
    if (q == 0) {
        if (s.find(0) != s.end()) {
            if (s.find(b) != s.end())
                printf("0\n");
            else
                printf("1\n");
        } else {
            printf("inf\n");
        }
        return 0;
    }
    if (q == 1) {
        if (s.find(b) != s.end()) {
            printf("0\n");
        } else {
            printf("inf\n");
        }
        return 0;
    } else if (q == -1) {
        if (s.find(b) != s.end() && s.find(-b) != s.end()) {
            printf("0\n");
        } else {
            printf("inf\n");
        }
        return 0;
    }
    int cnt = 0;
    for (; abs(b) <= l; b *= q) {
        if (s.find(b) != s.end()) {
            continue;
        }
        cnt++;
    }
    printf("%d\n", cnt);

} 

C. 再び関数#

この問題は思考問題と見なされるべきです

まず配列の差分前処理を行い、新しい配列を得ます

次にこの配列を使って正負変換を行います
+ - + - + - +
- + - + - + -
合計でこの 2 種類の配列しかなく、最大化の部分列を求めれば終了です

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <unordered_set>

using namespace std;

int a[100009];
int s[100008];

int main() {
//    freopen("input.txt", "r", stdin);
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < n - 1; i++) {
        s[i] = abs(a[i] - a[i + 1]);
    }
    int f=1;
    long long res = 0, now = 0, now2 = 0;
    for (int i = 0; i < n - 1; i++) {
        int current = s[i] * f;
        int current2 = s[i] *(-f);
        now += current;
        now2 += current2;
        if (now < 0)
            now = 0;
        if(now2<0)
            now2=0;
        res = max(max(res, now), now2);
        f *= -1;
    }
    printf("%I64d\n", res);

} 

D. 奇妙な旅#

この問題も思考問題とオイラー回路です
往復 2 回は 1 つの辺にもう 1 つの辺を追加することを意味します
オイラー回路の奇数度点は 0 または 2 のみです

  • 何の共通点もない 2 つの辺を削除 = オイラー回路ではない(奇数度点が 4 つあるため)
  • 共通点のある 2 つの辺を削除 = オイラー回路である(奇数度点が 2 つあるため)
  • 2 つの自己ループを削除 = オイラー回路である(奇数度点が 0 個あるため)
  • 1 つの自己ループと任意の 1 つの辺を削除 = オイラー回路である(奇数度点が 2 つあるため)
    これでおおよそ半分は解決しました

最初に連結グラフを判定することを忘れずに、disjoint set を利用します
次に数量を計算します
共通点のある 2 つの辺を削除する場合、各点を列挙し、その点の次数の 2 の組み合わせを取ることができます(すべての次数の辺の合計を列挙)
2 つの自己ループを削除する場合は、すべての自己ループの組み合わせの合計です
1 つの自己ループと任意の 1 つの辺を削除する場合は、すべての自己ループ × すべての辺(つまり自己ループと辺の組み合わせ)です

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <set>

typedef long long ll;

using namespace std;

struct edge {
    int x, y;
};

int deg[1000009] = {0};
edge edges[1000009];

int p[1000006];
int vis[1000006] = {0};
int n, m;

int getf(int x) {
    return x == p[x] ? x : (p[x] = getf(p[x]));
}

void _union(int x, int y) {
    x = getf(x), y = getf(y);
    p[x] = y;
}

bool connect() {
    for (int i = 0; i < n; i++) {
        p[i] = i;
    }
    for (int i = 0; i < m; i++) {
        _union(edges[i].x, edges[i].y);
    }
    set<int> bag;
    for (int i = 0; i < n; i++) {
        if (!vis[i])continue;
        bag.insert(getf(i));
    }
    return bag.size() <= 1;
}

ll loops = 0;

int main() {
//    freopen("input.txt", "r", stdin);
    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        x--;
        y--;
        edges[i].x = x;
        edges[i].y = y;
        vis[x] = 1;
        vis[y] = 1;
        if (x == y) {
            loops++;
        } else {
            deg[x]++;
            deg[y]++;
        }
    }
    if (!connect()) {
        printf("0\n");
        return 0;
    }
    ll cnt = 0;
    cnt += loops * (m - loops);
    cnt += loops * (loops - 1) / 2;
    for (int i = 0; i < n; i++) {
        cnt += (ll) (deg[i]) * (deg[i] - 1) / 2;
    }
    printf("%I64d", cnt);
} 
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。