The 2019 China Collegiate Programming Contest Harbin Site

目录

  • Contest Info
  • Solutions
    • A. Artful Paintings
    • E. Exchanging Gifts
    • F. Fixing Banners
    • I. Interesting Permutation
    • J. Justifying the Conjecture
    • K. Keeping Rabbits
    • L. LRU Algorithm

Contest Info



Practice Link

Solved A B C D E F G H I J K L
6/12 O - - - O O - - O O O !
  • O 在比赛中通过
  • ? 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Artful Paintings

题意:
有\(n\)个小球,可以选择给一些小球染色,但是需要满足以下限制条件:

  • 对于第\(i\)个第一类限制,需要满足标号在\([L_i, R_i]\)范围的小球被染色的个数需要大于等于\(k_i\)
  • 对于第\(i\)个第二类限制,需要满足标号在\([L_i, R_i]\)范围外的小球被染色的个数需要大于等于\(k_i\)

求最小的小球个数。

思路:
令\(S_i\)表示前\(i\)个小球的被染色数量,如下建图:

  • \(S_i - S_{i - 1} \geq 0\)
  • \(S_i - S_{i - 1} \leq 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\)具有单调性,二分,然后差分约束建图判断即可。

代码:

view code

#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. Exchanging Gifts

题意:
有\(n\)个序列,对于第\(i\)个序列,以以下两种方式之一给出:

  • \(S_i = [q_1, q_2, \cdots, q_k]\)
  • \(S_i = S_x + S_y\)

最后求\(S_n\)的最大欢乐值,这个欢乐值是重新排列序列中的数,某个位置\(i\),如果重排列后的数和原始的数不一样,那么这个位置提供一个欢乐值。

思路:
容易发现序列的欢乐值和序列的总个数以及出现次数最多的数的个数有关。
那么我们倒着做一遍,容易发现这是一个树结构,而对于直接给出的序列来说,他们是叶子结点,那么我们可以倒着标记一遍,这样可以标记出每个叶子结点出现多少次,然后暴力统计即可。

代码:

view code

#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. Fixing Banners

签到。

代码:

view code

#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. Interesting Permutation

题意:
有一个排列\(a_i\),现在生成\(f, g, h\):

  • \(\forall i \in [1, n], f_i = max\{a_1, a_2, \cdots, a_i\}\)
  • \(\forall i \in [1, n], g_i = min\{a_1, a_2, \cdots, a_i\}\)
  • \(\forall i \in [1, n], h_i = f_i - g_i\)

现在给出\(h_i\),求\(a_i\)的合法方案数。

代码:

view code

#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. Justifying the Conjecture

签到。

代码:

view code

#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. Keeping Rabbits

代码:

view code

#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 Algorithm

题意:
给出一个长度为\(n\)的操作序列,有\(q\)次询问,每次询问给出一个容量为\(m\)的cache,里面有一些元素,问这个操作序列使用\(LRU\)算法,并且cache容量在\(m\)的操作的过程中,
是否有一步这个cache里面的元素和询问给出的是一致的。

原文地址:https://www.cnblogs.com/Dup4/p/11790255.html

时间: 2024-07-29 07:40:36

The 2019 China Collegiate Programming Contest Harbin Site的相关文章

The 2019 China Collegiate Programming Contest Harbin Site F. Fixing Banners

链接: https://codeforces.com/gym/102394/problem/F 题意: Harbin, whose name was originally a Manchu word meaning "a place for drying fishing nets", grew from a small rural settlement on the Songhua River to become one of the largest cities in Northea

The 2019 China Collegiate Programming Contest Harbin Site K. Keeping Rabbits

链接: https://codeforces.com/gym/102394/problem/K 题意: DreamGrid is the keeper of n rabbits. Initially, the i-th (1≤i≤n) rabbit has a weight of wi. Every morning, DreamGrid gives the rabbits a carrot of weight 1 and the rabbits fight for the only carrot

The 2019 China Collegiate Programming Contest Harbin Site J. Justifying the Conjecture

链接: https://codeforces.com/gym/102394/problem/J 题意: The great mathematician DreamGrid proposes a conjecture, which states that: Every positive integer can be expressed as the sum of a prime number and a composite number. DreamGrid can't justify his c

The 2019 China Collegiate Programming Contest Harbin Site I. Interesting Permutation

链接: https://codeforces.com/gym/102394/problem/I 题意: DreamGrid has an interesting permutation of 1,2,-,n denoted by a1,a2,-,an. He generates three sequences f, g and h, all of length n, according to the permutation a in the way described below: For ea

The 2019 China Collegiate Programming Contest Harbin Site I - Interesting Permutation 思维

//#include<bits/stdc++.h> #include<map> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define int long long using namespace std; #define rep_1(i,m,n) for(int i=m;i<=n

The 2019 China Collegiate Programming Contest Harbin Site A - Artful Paintings 差分约束

#include<map> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int N=1e5+5; const int M=1e5+5; const int INF=0x3f3f3f3f; int read(

The 2019 China Collegiate Programming Contest Harbin Site E - Exchanging Gifts 拓扑图+离散化

非常难受的是,我用链表写的,要么wa,要么tle,甚至还出现了超内存... 然后换成矩阵,开始还是wa了两次,然后换了别的快读,才过,难受. #include<map> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; #

2019 China Collegiate Programming Contest Qinhuangdao Onsite

目录 Contest Info Solutions A. Angle Beats D. Decimal F. Forest Program I. Invoker J. MUV LUV EXTRA Contest Info Practice Link Solved A B C D E F G H I J K L 5/12 O - - O - O - - - O ? - O 在比赛中通过 ? 赛后通过 ! 尝试了但是失败了 - 没有尝试 Solutions A. Angle Beats 题意: 给出

2018 China Collegiate Programming Contest Final (CCPC-Final 2018)(A B G I L)

A:签到题,正常模拟即可. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5 + 5; 4 struct node{ 5 int id, time; 6 }; 7 node a[maxn]; 8 bool cmp(const node &a, const node &b){ 9 if(a.id^b.id) return a.id < b.id; 10 else return a.