2019年中国大学対抗プログラミングコンテストハルビンサイト

コンテスト情報


練習リンク

解決済み A B C D E F G H J K L
6/12 ザ・ - - - ザ・ ザ・ - - ザ・ ザ・ ザ・
  • ゲームを通じてO
  • ゲームによって後Ø
  • !私が試みたが失敗しました
  • - いいえ試みません

ソリューション


A.巧みな絵画

質問の意味:
そこ\(N \)ボール、あなたには、いくつかの小さなボールを染色することを選択したが、以下の制限事項を満たすために必要なことができます。

  • 最初のため\(Iは\)ファーストクラスの制限の、数字満たすために必要\を([L_iを、R_iを] \ ) のペレットの数の範囲染色の以上である必要が\(K_I \)
  • 最初のために(私は\)\第2カテゴリー制限は数字を満たす必要がある([L_iを、R_iを] \ \ ) ペレットの範囲外の数が染色さ以上である必要が\(K_I \)

最低限の必要なボールの数が少ないです。

アイデア:
作る\(S_I \)を表現する前に(私は\)\少量建て図面として、ボールを染色しています。

  • \(S_I - S_ {I - 1} \ GEQ 0 \)
  • \(S_I - S_ {I - 1} \当量1 \)
  • 最初の制限:\(S_のR_iを{} - S_のL_iを{ - } 1 \ GEQ K_I \)。
  • 第二のカテゴリーの制限:\(S_N - (S_のR_iを{} - S_のL_iを{ - } 1)\ GEQ K_I \)。

ビーズの総数を見つけることは容易で\(S_N \)単調な、2つの点を、その後、差動制約が図に決定される構築。

コード:


ビューコード

#include <bits/stdc++.h>
using namespace std;
using pII = pair <int, int>;
#define fi first
#define se second
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n, M1, M2, Maxk;
int dis[N], inq[N], cnt[N];
int que[N], ql, qr;
struct Edge {
    int v, w;
    Edge() {}
    Edge(int v, int w): v(v), w(w) {}
    bool operator < (const Edge &other) const {
        return w < other.w;
    }
};
vector <vector<Edge>> G;
struct node {
    int l, r, k;
    void input() {
        scanf("%d %d %d", &l, &r ,&k);
        Maxk = max(Maxk, k);
    }
}q1[N], q2[N];

inline void Init() {
    G.clear(); G.resize(n + 1);
    for (int i = 0; i <= n; ++i) {
        inq[i] = 0, cnt[i] = 0, dis[i] = INF;
    }
}

inline void addedge(int u, int v, int w) {
    G[u].push_back(Edge(v, w));
}

bool SPFA(int x) {
    for (int i = 0; i <= n; ++i) {
        inq[i] = cnt[i] = 0;
        dis[i] = INF;
    }
    dis[0] = 0;
    inq[0] = 1;
    queue <int> q;
    q.push(0);
    int limit = min(n, max(10, n / 2));
    while (!q.empty()) {
        int u = q.front(); q.pop();
        inq[u] = 0;
        for (auto &it : G[u]) {
            int v = it.v, w = it.w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!inq[v]) {
                    inq[v] = 1;
                    q.push(v);
                    if (++cnt[v] > limit) return false;
                }
            }
        }
    }
    return dis[n] == x;
}

bool check(int x) {
    G.clear(); G.resize(n + 1);
    for (int i = 1; i <= M1; ++i) {
        int l = q1[i].l - 1, r = q1[i].r, k = q1[i].k;
        addedge(r, l, -k);
    }
    for (int i = 1; i <= M2; ++i) {
        int l = q2[i].l - 1, r = q2[i].r, k = q2[i].k;
        addedge(l, r, x - k);
    } 
    for (int i = 1; i <= n; ++i) {
        addedge(i, i - 1, 0);
        addedge(i - 1, i, 1);
    }
    addedge(0, n, x);
    addedge(n, 0, -x);
    return SPFA(x);
}

int main() {   
    int T;  
    scanf("%d", &T);  
    while (T--) {  
        scanf("%d %d %d", &n, &M1, &M2); 
        Maxk = 0;   
        for (int i = 1; i <= M1; ++i) q1[i].input(); 
        for (int i = 1; i <= M2; ++i) q2[i].input(); 
        int l = Maxk, r = n - 1, res = n;
        while (r - l >= 0) {
            int mid = (l + r) >> 1;
            if (check(mid)) {
                r = mid - 1;
                res = mid;
            } else {
                l = mid + 1;
            }
        }
        printf("%d\n", res);
    }
    return 0;
}

E.は、ギフトを交換します

問題の意味:
ある\(N- \)最初のシーケンス、\(私は\)の2つの方法の1に与えられる配列、:

  • \(S_I = [Q_1、Q_2、\ cdots、q_k] \)
  • \(S_I = S_x + S_y \)

最後に、尋ねる\(S_N \)シーケンス番号、位置再配置する喜びの最大値を、この値の喜びである\(iは\)再配置後と、番号を番号ではなく、元と同じであるので、これは場所を提供する場合喜び値。

アイデア:
シーケンスと最も出現順序番号の総数について喜びの数と値を見つけるのは簡単。
その後、我々は再び後方にそれを行うには、ツリー構造を見つけるのは簡単で、かつ特定のダイレクトシーケンスのために、彼らはその後、我々は後方再びマークすることができますので、あなたは、各リーフノードがずっと表示されたマークすることができ、リーフノードであります回、そして暴力の統計情報をすることができます。

コード:


ビューコード

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6 + 10;
struct Hash {
    int a[N];
    void init() { *a = 0; }
    void add(int x) { a[++*a] = x; }
    void gao() { sort(a + 1, a + 1 + *a); *a = unique(a + 1, a + 1 + *a) - a - 1; }
    int get(int x) { return lower_bound(a + 1, a + 1 + *a, x) - a; }
}hs;
int n, m, x[N], y[N], op[N], sze[N]; 
ll a[N], b[N];
vector <vector<int>> vec;

int main() {
    int _T; scanf("%d", &_T);
    while (_T--) {
        scanf("%d", &n);
        memset(b, 0, sizeof (b[0]) * (n + 10));
        vec.clear(); vec.resize(n + 1);
        hs.init();
        for (int i = 1; i <= n; ++i) {
            scanf("%d", op + i);
            if (op[i] == 1) {
                scanf("%d", sze + i);
                vec[i].resize(sze[i]);
                for (int j = 0; j < sze[i]; ++j) {
                    scanf("%d", &vec[i][j]);
                    hs.add(vec[i][j]);
                }
            } else {
                scanf("%d%d", x + i, y + i);
            }
        }
        hs.gao();
        m = hs.a[0];
        memset(a, 0, sizeof (a[0]) * (m + 10));
        b[n] = 1;
        for (int i = n; i >= 1; --i) {
            if (b[i] == 0) continue;
            if (op[i] == 1) {
                for (int j = 0; j < sze[i]; ++j) {
                    vec[i][j] = hs.get(vec[i][j]);
                    a[vec[i][j]] += b[i];
                }
            } else {
                b[x[i]] += b[i];
                b[y[i]] += b[i];
            }
        }
        ll tot = 0, Max = 0;
        for (int i = 1; i <= m; ++i) {
            tot += a[i];
            Max = max(Max, a[i]);
        }
        ll res = 0;
        if (Max <= tot / 2) res = tot;
        else res = (tot - Max) * 2;
        printf("%lld\n", res);  
    }
    return 0;
}

F.はバナーを修正します

ログインしてください。

コード:


ビューコード

#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
char s[N];
int a[6][210]; 
vector <int> id;

bool ok() {
    char *str = "harbin";
    for (int i = 0; i < 6; ++i) {
        if (a[id[i]][str[i]] == 0)
            return false;
    }
    return true;
}

void gao() {
    do {
        if (ok()) {
            puts("Yes");
            return;
        }
    } while (next_permutation(id.begin(), id.end()));
    puts("No");
}

int main() {
    int _T; scanf("%d", &_T);
    while (_T--) {
        for (int i = 0; i < 6; ++i) {
            a[i]['h'] = 0;
            a[i]['a'] = 0;
            a[i]['r'] = 0;
            a[i]['b'] = 0;
            a[i]['i'] = 0;
            a[i]['n'] = 0;
            scanf("%s", s + 1);
            for (int j = 1, len = strlen(s + 1); j <= len; ++j) {
                a[i][s[j]] = 1;
            }
        }
        id.clear();
        for (int i = 0; i < 6; ++i) id.push_back(i);
        gao();
    }
    return 0;
}

I.興味深い順列

問題の意味は:
そこに配置されている(a_iを\)\を今生成する、\(F、G、Hは、\)

  • \(\ iは[1、N]で\ FORALL、のf_i = maxの\ {A_1、A_2、\ cdots、a_iを\} \)
  • \(\ iは[1、N]で\ FORALL、g_i =分\ {A_1、A_2、\ cdots、a_iを\} \)
  • \(\ FORALL iはH_I =のf_i、[1、N]で\ - g_i \)

今、与えられた\(H_I \) 求めている\(a_iを\)法的なプログラムの数。

コード:


ビューコード

#include <bits/stdc++.h>

using namespace std;

const int MOD = 1e9 + 7;

long long cntt[100000 + 10];
int x[100000 + 10];

int main() {
    int T;
    scanf("%d", &T);
    cntt[0] = 1;
    for (int i = 1; i <= 100000; ++i) cntt[i] = (cntt[i - 1] * 2) % MOD;
    while (T--) {
        int n;
        int Max, flag;
        long long ans, q = 1, t = 0, cnt;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) scanf("%d", &x[i]);
        if (n == 1) {
            if (x[1] == 0) flag = 0;
            else flag = 1;
        }
        else { 
            if (x[1] == 0) {
                flag = 0; ans = 0; Max = x[1]; q = 1; t = 0; cnt = 0;
                for (int i = 2; i <= n; ++i) {
                    if (flag == 0) {
                        if (x[i] > Max) {
                            ++t; cnt += (x[i] - Max - 1);
                            Max = x[i];
                            if (Max > n - 1) flag = 1;
                        }
                        else if (x[i] == Max) {
                            if (cnt > 0) {
                                q = (q * cnt) % MOD;
                                cnt--;      
                            }
                            else flag = 1;
                        }
                        else {
                            flag = 1;
                        }
                    }
                }
            }
            else flag = 1;
        }
        //printf("f %d\n", flag);
        if (flag == 1) printf("0\n");
        else {
            ans = cntt[t] * q % MOD;
            printf("%lld\n", ans);
        }
    }
    return 0;
}

J.予想を正当化します

ログインしてください。

コード:


ビューコード

#include <bits/stdc++.h>
using namespace std;

int main() {
    int _T; scanf("%d", &_T);
    while (_T--) {
        int n; scanf("%d", &n);
        if (n < 6) puts("-1");
        else if (n % 2 == 0) printf("%d %d\n", 2, n - 2);
        else printf("%d %d\n", 3, n - 3);
    }
    return 0;
}

K.はウサギを維持します

コード:


ビューコード

#include <bits/stdc++.h>

using namespace std;

using db = double;

const int N = 1e5 + 10;

int n, k;
db w[N];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &k);
        db sum = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%lf", w + i);
            sum += w[i];
        }
        for (int i = 1; i <= n; ++i) {
            w[i] += k * w[i] / sum;
        }
        for (int i = 1; i <= n; ++i) {
            printf("%.10f%c", w[i], " \n"[i == n]);
        }
    }
    return 0;
}

L. LRUアルゴリズム

問題の意味:
長さ指定された\(N- \)一連の操作がある\(Q \)回のクエリ、容量の与えられたそれぞれを求めて\(m個\)キャッシュでは、いくつかの要素がありますが、この操作は頼みます使用シーケンス\(LRU \)アルゴリズム、及びキャッシュ容量\(m個\)動作中に、
キャッシュ要素は一貫して問い合わせ与えられたステップがある場合。

おすすめ

転載: www.cnblogs.com/Dup4/p/11790255.html