• KEYENCE Programming Contest 2019 Solution


    A - Beginning

    签到.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int a[4];
     7     while (scanf("%d", a) != EOF)
     8     {
     9         for (int i = 1; i < 4; ++i) scanf("%d", a + i);
    10         sort(a, a + 4);
    11         int res = 0;
    12         for (int i = 0; i < 4; ++i) res = res * 10 + a[i];
    13         puts(res == 1479 ? "YES" : "NO");
    14     }
    15     return 0;
    16 }
    View Code

    B - KEYENCE String

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 string s;
     5 
     6 string get(int pos)
     7 {
     8     string res = "";
     9     for (int i = 0; i <= pos; ++i) res += s[i];
    10     int len = s.size();
    11     for (int i = len - (7 - pos - 1); i < len; ++i) res += s[i];
    12     return res;
    13 }
    14 
    15 bool work()
    16 {
    17     for (int i = 0; i < 7; ++i)
    18     {
    19         string tmp = get(i);
    20         if (tmp == "keyence") return 1;
    21     }
    22     return 0;
    23 }
    24 
    25 int main()
    26 {
    27     while (cin >> s) puts(work() ? "YES" : "NO");
    28     return 0;
    29 }
    View Code

    C - Exam and Wizard

    Solved.

    题意:

    给出些个数字$A_i, 和 B_i$

    要求构造$C_i 使得 C_i >= B_i 并且 sum A_i = sum C_i$

    并且使得变动的数字个数最少

    思路:

    先弄出不足的部分,然后取差值最大的$A_i > B_i$ 的部分用堆维护,每次取最大的贡献出来补充

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 100010
     5 #define ll long long
     6 int n, a[N], b[N];
     7 
     8 int main()
     9 {
    10     while (scanf("%d", &n) != EOF)
    11     {
    12         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    13         for (int i = 1; i <= n; ++i) scanf("%d", b + i);
    14         ll need = 0;
    15         priority_queue <int, vector <int>, less <int> > pq;
    16         int res = 0; 
    17         for (int i = 1; i <= n; ++i) 
    18         {
    19             if (b[i] > a[i]) need += b[i] - a[i], ++res;
    20             else if (b[i] < a[i]) pq.push(a[i] - b[i]);
    21         }
    22         while (!pq.empty() && need > 0)
    23         {
    24             int top = pq.top(); pq.pop();
    25             need -= top; ++res;    
    26         }
    27         if (need > 0) puts("-1");
    28         else printf("%d
    ", res);
    29     }
    30     return 0;
    31 }
    View Code

    D - Double Landscape

    Upsolved.

    题意:

    在$n * m的矩阵中填数,每行中最大的数为a_i, 每列中最大的数为b_i$

    求填数方案

    思路:

    对于某个数$x$

    如果它存在于多个$a_i 中 或者多个 b_i 中 $

    那么无解

    再考虑

    它既存在于$a_i 也存在于 b_i 中

    那么它的位置是确定的$

    它只存在于某个$a_i或者某个b_i中$

    那么它的方案数就是那一列或者那一行的$a_i$比它大的数的个数

    它不存在于某个$a_i或者某个b_i中$

    那么它的方案数是 $a_i > a_x 的个数 cdot b_i > b_x的个数$

    但是要减去比它大的数的个数

    因为它能填的位置,比它大的数都能填,而且是子集关系

    所以要让出一位

    但是对于第二种情况不用考虑,因为第二种情况的那个数肯定是当前行或者当前列最大的

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 1100
     6 const ll MOD = (ll)1e9 + 7;
     7 int n, m, a[N], b[N];
     8 
     9 bool check()
    10 {
    11     for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j)
    12         if (a[i] == a[j]) return false;
    13     for (int i = 1; i <= m; ++i) for (int j = i + 1; j <= m; ++j)
    14         if (b[i] == b[j]) return false; 
    15     return true; 
    16 }
    17 
    18 int main()
    19 {
    20     while (scanf("%d%d", &n, &m) != EOF)
    21     {
    22         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    23         for (int i = 1; i <= m; ++i) scanf("%d", b + i);
    24         sort(a + 1, a + 1 + n);
    25         sort(b + 1, b + 1 + m);
    26         if (!check()) puts("0");  
    27         else
    28         {
    29             a[n + 1] = n + 1;
    30             b[m + 1] = m + 1;
    31             int l[2] = {0, 0};
    32             ll res = 1; 
    33             for (int i = 1; i <= n * m; ++i)
    34             {
    35                 while (l[0] <= n && a[l[0]] < i) ++l[0]; 
    36                 while (l[1] <= m && b[l[1]] < i) ++l[1];
    37                 ll d = 0;
    38                 if (a[l[0]] == i && b[l[1]] == i)
    39                     d = 1;
    40                 else if (a[l[0]] == i && b[l[1]] != i)
    41                     d = m - l[1] + 1;
    42                 else if (b[l[1]] == i && a[l[0]] != i)
    43                     d = n - l[0] + 1;
    44                 else
    45                     d = (m - l[1] + 1) * (n - l[0] + 1) - (n * m - i);
    46                 res = (res * d) % MOD; 
    47             } 
    48             printf("%lld
    ", res);
    49         }
    50     }
    51     return 0;
    52 }
    View Code

    E - Connecting Cities

    Upsolved.

    题意:

    $n个城市,两个城市之间的边权是 |i - j| cdot D + A_i + A_j$

    求最小生成树

    思路:

    考虑将区间分成两部分

    分别为$[l, mid] 和 [mid +1, r]$

    考虑

    左区间为$f[i] = a[i] - d * i$

    右区间为$g[i] = a[i] + d * j$

    令$f[0] 和 g[0] 为 Min(f[i]), g[0] 为 Min(g[i])$

    那么我们将$(i, j_0), (i_0, j), (i_0, j_0) 连边$

    我么考虑$(i, j)这种边一定比上面三种边的边权要大$

    那么假设我们需要$(i, j)这种边来增加连通性,那么上面那三种边必定能满足$

    所以分治建边 一共有$NlogN级别的边数 $

    再做MST

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 200010
     6 #define INFLL 0x3f3f3f3f3f3f3f3f
     7 int n, m;
     8 ll d, a[N];
     9 struct Edge
    10 {
    11     int u, v; ll w;
    12     Edge() {}
    13     Edge(int u, int v, ll w) : u(u), v(v), w(w) {}
    14     bool operator < (const Edge &other) const { return w < other.w; }
    15 }edge[N * 30];
    16 
    17 void add(int l, int r)
    18 {
    19     if (l == r) return;
    20     int mid = (l + r) >> 1;
    21     ll Min = INFLL; int pos = -1; 
    22     for (int i = l; i <= mid; ++i) 
    23     {
    24         ll f = a[i] - d * i;
    25         if (f < Min)
    26         {
    27             Min = f;
    28             pos = i;
    29         }
    30     }
    31     for (int i = mid + 1; i <= r; ++i)
    32         edge[++m] = Edge(pos, i, a[pos] + a[i] + d * (i - pos));
    33     Min = INFLL; pos = -1;
    34     for (int i = mid + 1; i <= r; ++i)
    35     {
    36         ll f = a[i] + d * i;
    37         if (f < Min)
    38         {
    39             Min = f;
    40             pos = i;
    41         }
    42     }
    43     for (int i = l; i <= mid; ++i) 
    44         edge[++m] = Edge(pos, i, a[pos] + a[i] + d * (pos - i));
    45     add(l, mid);
    46     add(mid + 1, r);
    47 }
    48 
    49 int pre[N];
    50 int find(int x) { return pre[x] == 0 ? x : pre[x] = find(pre[x]); }
    51 ll Kruskal()
    52 {
    53     memset(pre, 0, sizeof pre);
    54     sort(edge + 1, edge + 1 + m);
    55     int cnt = 1;
    56     ll res = 0;
    57     for (int i = 1; i <= m; ++i)
    58     {
    59         int u = edge[i].u, v = edge[i].v; ll w = edge[i].w;
    60         int fu = find(u), fv = find(v);
    61         if (fu == fv) continue;
    62         pre[fu] = fv;
    63         res += w;
    64         ++cnt;
    65         if (cnt == n) return res;
    66     }
    67     return res;
    68 }
    69 
    70 int main()
    71 {
    72     while (scanf("%d%lld", &n, &d) != EOF)
    73     {
    74         m = 0;
    75         for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
    76         add(1, n);
    77         printf("%lld
    ", Kruskal());
    78     }
    79     return 0;
    80 }
    View Code

    法二:

    按$a_i大小排序$

    每次对于当前$x, 在所有a_j <= a_x的 城市当中,对于在它两侧的,各选出一条最短边连边$

    为什么这样贪心是对的

    我们考虑假如存在一个城市$z; a_z < a_i, 并且假设最短边的城市是y$

    那么$(x, y) 和 (y, z) 都小于 (x, z)$

    所以$(x, z)这条边一定不在MST中$

    考虑这样证明

    $dist(x, y) < dist(x, z) 非常显然$

    考虑$dist(y, z) < dist(x, z)$

    首先假设$z < y < x$

    $dist(y, z) = a_y +a_z + d * (y - z)$

    $dist(x, z) = a_x + a_z + d * (x - z)$

    $dist(x, z) - dist(y, z) = a_x - a_y + d * (x - y) >= 0$

    得证

    再考虑$y < z < x$

    $dist(x, y) = a_x + a_y + d * (x - y)$

    $dist(z, y) = a_z + a_y + d * (z - y)$

    $dist(x, y) - dist(z, y) = a_x - a_z + d * (x - z) >= 0$

    又因为 $dist(x, y) <= dist(x, z)$

    所以$dist(x, z) >= dist(x, y) >= dist(z, y)$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define ll long long
      5 #define N 200010
      6 #define INFLL 0x3f3f3f3f3f3f3f3f
      7 int n, m;
      8 ll d;
      9 struct node
     10 {
     11     int id; ll v;
     12     void scan(int id)
     13     {
     14         this->id = id;
     15         scanf("%lld", &v);
     16     }
     17     bool operator < (const node &other) const { return v < other.v; }
     18 }a[N];
     19 struct Edge
     20 {
     21     int u, v; ll w;
     22     Edge () {}
     23     Edge (int u, int v, ll w) : u(u), v(v), w(w) {}
     24     bool operator < (const Edge &other) const { return w < other.w; }
     25 }edge[N << 2];
     26 
     27 struct SEG
     28 {
     29     struct node
     30     {
     31         ll Min; int pos;
     32         node () {}
     33         node (ll Min, int pos) : Min(Min), pos(pos) {}
     34         void init() { Min = INFLL, pos = -1; }
     35         node operator + (const node &other) const
     36         {
     37             node res; res.init();
     38             if (Min < other.Min)
     39             {
     40                 res.Min = Min;
     41                 res.pos = pos;
     42             }
     43             else
     44             {
     45                 res.Min = other.Min;
     46                 res.pos = other.pos;
     47             }
     48             return res;
     49         }
     50     }a[N << 2], res;
     51     void build(int id, int l, int r)
     52     {
     53         a[id].init(); 
     54         if (l == r) return;
     55         int mid = (l + r) >> 1;
     56         build(id << 1, l, mid);
     57         build(id << 1 | 1, mid + 1, r);
     58     }
     59     void update(int id, int l, int r, int pos, ll v)
     60     {
     61         if (l == r) 
     62         {
     63             a[id] = node(v, pos);
     64             return;
     65         }
     66         int mid = (l + r) >> 1;
     67         if (pos <= mid) update(id << 1, l, mid, pos, v);
     68         else update(id << 1 | 1, mid + 1, r, pos, v);
     69         a[id] = a[id << 1] + a[id << 1 | 1];
     70     }
     71     void query(int id, int l, int r, int ql, int qr)
     72     {
     73         if (qr < ql) return;
     74         if (l >= ql && r <= qr)
     75         {
     76             res = res + a[id];
     77             return;
     78         }
     79         int mid = (l + r) >> 1;
     80         if (ql <= mid) query(id << 1, l, mid, ql, qr);
     81         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
     82     }
     83 }seg[2];
     84 
     85 int pre[N];
     86 int find(int x) { return pre[x] == 0 ? x : pre[x] = find(pre[x]); }
     87 ll Kruskal()
     88 {
     89     memset(pre, 0, sizeof pre);
     90     sort(edge + 1, edge + 1 + m);
     91     int cnt = 1;
     92     ll res = 0;
     93     for (int i = 1; i <= m; ++i)
     94     {
     95         int u = edge[i].u, v = edge[i].v; ll w = edge[i].w;
     96         int fu = find(u), fv = find(v);
     97         if (fu == fv) continue;
     98         pre[fu] = fv;
     99         ++cnt;
    100         res += w;
    101         if (cnt == n) return res;
    102     }
    103     return res;
    104 }
    105 
    106 int main()
    107 {
    108     while (scanf("%d%lld", &n, &d) != EOF)
    109     {    
    110         m = 0;
    111         for (int i = 1; i <= n; ++i) a[i].scan(i);
    112         for (int i = 0; i < 2; ++i) seg[i].build(1, 1, n);
    113         sort(a + 1, a + 1 + n);
    114         for (int i = 1; i <= n; ++i)
    115         {
    116             int u = a[i].id, v;
    117             for (int j = 0; j < 2; ++j)
    118                 seg[j].res.init();
    119             seg[0].query(1, 1, n, 1, u - 1);
    120             seg[1].query(1, 1, n, u + 1, n);
    121             for (int j = 0; j < 2; ++j) if (seg[j].res.pos != -1)
    122             {
    123                 v = seg[j].res.pos;
    124                 edge[++m] = Edge(u, v, a[i].v + 1ll * (j ? -1 : 1) * d * u + seg[j].res.Min);
    125             }
    126             seg[0].update(1, 1, n, u, a[i].v - d * u);
    127             seg[1].update(1, 1, n, u, a[i].v + d * u);
    128         }
    129         printf("%lld
    ", Kruskal());
    130     }
    131     return 0;
    132 }
    View Code
  • 相关阅读:
    docker-compose 使用
    mysql UNIX时间戳与日期的相互转换 查询表信息
    mysql查看表结构命令
    PostgreSQL新手入门
    ibdata1是?
    ubuntu 12.04 安装 nginx+php+mysql web服务器
    读懂IL代码就这么简单(二)
    读懂IL代码就这么简单(一)
    在Ubuntu Linux下怎样安装QQ
    jQuery 选择器
  • 原文地址:https://www.cnblogs.com/Dup4/p/10265066.html
Copyright © 2020-2023  润新知