zoukankan      html  css  js  c++  java
  • Codeforces Round #577 (Div. 2)

    A - Important Exam

    题意:n个人,m道题,每道题有A B C D E五个选项,每个人在每道题都有一个选项,每道题有一个分值,问所有人的分值总和最多为多少。

    分析:对某道题,他的分值是固定的,总共有n个人作答,挑选5个选项中选的人最多的作为答案,可得到分数最多。

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 #include <iostream>
     5  
     6 #define maxn 1000005
     7 #define mod 1000000007
     8 #define inf 0x3f3f3f3f
     9 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    10 #define ll long long
    11 using namespace std;
    12 string a[1005];
    13 ll b[1005][10];
    14  
    15 int main() {
    16     start;
    17     int n, m;
    18     cin >> n >> m;
    19     for (int i = 1; i <= n; ++i) {
    20         cin >> a[i];
    21         for (int j = 0; j < m; ++j)
    22             b[j][a[i][j] - 'A']++;
    23     }
    24     ll ans = 0;
    25     for (int i = 0; i < m; ++i) {
    26         int x;
    27         cin >> x;
    28         ll maxt = 0;
    29         for (int j = 0; j < 5; ++j)
    30             maxt = max(maxt, b[i][j]);
    31         ans += maxt * x;
    32     }
    33     cout << ans << endl;
    34     return 0;
    35 }
    View Code

    B - Zero Array

    题意:给n个数,每次挑不同的两个数同时减一,问数组能否全变为0。

    分析:如果数总和为奇数,显然不行。如果最大的数比其他所有数加起来都大,显然不行。其余我们分析:总和为偶数,对于数组,我们任意挑两个,并保证挑选均匀(每次挑选最大的和最小的,各减一),即可成立。(我也不会证,但感觉上是对的)。

     1 #include <bits/stdc++.h>
     2  
     3 #define maxn 200005
     4 #define mod 1000000007
     5 #define inf 0x3f3f3f3f
     6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     7 #define ll long long
     8 using namespace std;
     9 #define int ll
    10  
    11 signed main() {
    12     start;
    13     int n;
    14     ll ans = 0;
    15     ll maxt = 0;
    16     cin >> n;
    17     for (int i = 1; i <= n; ++i) {
    18         int x;
    19         cin >> x;
    20         ans += x;
    21         maxt = max(maxt, x);
    22     }
    23     if (ans & 1 || maxt * 2 > ans)
    24         cout << "NO" << endl;
    25     else
    26         cout << "YES" << endl;
    27     return 0;
    28 }
    View Code

    C - Maximum Median

    题意:给n(n为奇数)个数,和k个加一的机会,问操作后数组中位数是多少。

    分析:排序后,对于第n/2+1之前的数,肯定是不进行加一操作了,否则这个加一操作给到后n/2+1个数肯定更有效。令mid=n/2+1,要保证a[mid]越来越大(如果后n/2个数越来越大,答案仍然是a[mid],操作无效)。

    第一次操作,将a[mid]加到a[mid+1](如果加不到则将k全部加在a[mid]上)。

    第二次操作,将a[mid]和a[mid+1]加到a[mid+2](如果加不到则将剩余的k均匀分到a[mid],a[mid]上)。

    ……

    第n/2次操作,将a[mid],a[mid+1],……,a[n-1]加到a[n](如果加不到则将剩余的k均匀分到a[mid],a[mid+1],……,a[n-1]上)

    第n/2+1次操作,将剩余的k均匀分到a[mid],a[mid+1],……,a[n]上

     1 #include <bits/stdc++.h>
     2 
     3 #define maxn 200005
     4 #define mod 1000000007
     5 #define inf 0x3f3f3f3f
     6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     7 #define ll long long
     8 using namespace std;
     9 #define int ll
    10 int a[maxn];
    11 
    12 signed main() {
    13     start;
    14     int n, k;
    15     cin >> n >> k;
    16     for (int i = 1; i <= n; ++i)
    17         cin >> a[i];
    18     sort(a + 1, a + n + 1);
    19     int mid = n / 2 + 1;
    20     if (a[mid] + k < a[mid + 1]) {
    21         cout << a[mid] + k << endl;
    22         return 0;
    23     }
    24     int t = 1;
    25     for (int i = 1; mid + i <= n; ++i) {
    26         if (k - (a[mid + i] - a[mid]) * i < 0)
    27             break;
    28         t = i + 1;
    29         k -= (a[mid + i] - a[mid]) * i;
    30         a[mid] = a[mid + i];
    31     }
    32     a[mid] += (k / t);
    33     cout << a[mid];
    34     return 0;
    35 }
    View Code

    D - Treasure Hunting

    个人觉得难度不止2000,赛终只有369人AC(我显然不在其中),而前三题难度最大的B却有2520人AC,难度梯度设计不太合理。但这也不是我前三题wa8发的理由,掉分就完事了,承认自己菜。赛后看了看rank 1大神的代码,看了一个小时终于看懂了。

    题意:n行m列的方格,有k个宝藏,和q个安全列。从(1,1)出发,只能走上、左、右三个方向。走上时,只能从安全列往上。问将所有宝藏捡完最少需要多少步。

    分析:

    一、对于第i行,我们是从第j列升上来的,我们只考虑最左边和最右边的宝藏,设最左边的宝藏在第l列,最右边的宝藏在第r列。

    二、假设先拿最右边的宝藏(拿左边宝藏的情况见补充),那么拿到最左边的宝藏需要abs(j-l)+abs(l-r)步,再考虑离l最近的两个安全列(如果l左边没有则只考虑右边一个),设为q和w。

    三、我们对第i行后的第一个有宝藏的行(第i+1行不一定有宝藏)来说(设为s),我们是从第q列和第w列升上来的。

    四、再看第i+1行的l2和r2,假设也先拿最左边的宝藏,如果是从第q列升上来的,我们从第i行刚升上来到最左边的宝藏共要走abs(j-l)+abs(l-r)+s+abs(q-l2)+abs(l2-r2);如果是从w列升上来的,则走abs(j-l)+abs(l-r)+s+abs(w-l2)+abs(l2-r2),我们自然取最小的了。

    五、取完之后再考虑李l2最近的两个两个安全列(如果l左边没有则只考虑右边一个),进入第三步。

    补充:第一行默认从第一列升上来的,且显然先取右边宝藏。

    对于第一步的第j列是从第一行递推上来的,实际上这个j分最多四种情况。

    对于第二步和第三步,要同时考虑先拿最左边和最右边的情况,所以一行我们需要考虑最多四列,四列走到后一行的最左边或者最右边各取最小值,再延伸出四列。

    大神代码(用个人风格改写了一下):

     1 #include <bits/stdc++.h>
     2 
     3 #define maxn 200005
     4 #define mod 1000000007
     5 #define inf 0x3f3f3f3f3f3f3f3f
     6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     7 #define ll long long
     8 using namespace std;
     9 
    10 struct node {
    11     int x, y;
    12 
    13     bool operator<(const node &b) const {
    14         if (x != b.x)
    15             return x < b.x;
    16         return y < b.y;
    17     }
    18 
    19     node(int x = 0, int y = 0) : x(x), y(y) {}
    20 };
    21 
    22 vector<node> treasures;
    23 vector<int> safe;
    24 
    25 signed main() {
    26     start;
    27     int n, m, k, q;
    28     cin >> n >> m >> k >> q;
    29     for (int i = 0; i < k; ++i) {
    30         int x, y;
    31         cin >> x >> y;
    32         treasures.emplace_back(x, y);
    33     }
    34     treasures.emplace_back(1, 1);
    35     ++k;
    36     for (int i = 0; i < q; ++i) {
    37         int x;
    38         cin >> x;
    39         safe.push_back(x);
    40     }
    41     sort(treasures.begin(), treasures.end());//先按行排列,后按列排列
    42     sort(safe.begin(), safe.end());//将安全列排列
    43     map<ll, ll> selected_col;//first为上次找宝藏所在列选择的安全列(最多为4),second为这种情况的步数
    44     selected_col[1] = 0;//默认第一行是从第1列升上来的
    45     ll ans;
    46     int current_row = 1;//上一个讨论的行,对于第一行来说不存在
    47     for (int i = 0, j = 0; i < k; i = j) {//j为下一列的第一个宝藏的指针
    48         while (j < k && treasures[j].x == treasures[i].x)//将j移动到后一行第一个宝藏处
    49             ++j;
    50         int row = treasures[i].x;//现在讨论的行
    51         ll l = treasures[i].y, r = treasures[j - 1].y;//该行最左边和最右边的两个宝藏的列数
    52         for (auto &it:selected_col)//&很重要
    53             it.second += row - current_row;//每种情况都加上上升需要的必要步数,所以current_row初始化为1
    54         current_row = row;//转移
    55         map<ll, ll> mint;//first为l和r,second为这种情况上一个宝藏所在列到l或者r的最小步数。
    56         mint[l] = mint[r] = inf;
    57         for (auto &it:selected_col) {
    58             mint[l] = min(mint[l], it.second + abs(it.first - r) + abs(l - r));
    59             mint[r] = min(mint[r], it.second + abs(it.first - l) + abs(r - l));
    60         }
    61         ans = min(mint[l], mint[r]);
    62         selected_col.clear();
    63         for (auto &it:mint) {
    64             /*找到离it.first(只有l或者r)最近的两个宝藏*/
    65             //吐槽下这里如果r右边没有安全列,又没有哨兵,会出事
    66             int safe_index = lower_bound(safe.begin(), safe.end(), it.first) - safe.begin();
    67             int safe_col = safe[safe_index];
    68             //cout << safe_col << endl;
    69             ll cost = it.second + abs(it.first - safe_col);
    70             if (selected_col.find(safe_col) == selected_col.end() || cost < selected_col[safe_col])
    71                 selected_col[safe_col] = cost;
    72             if (safe_index > 0) {
    73                 --safe_index;
    74                 safe_col = safe[safe_index];
    75                 cost = it.second + abs(it.first - safe_col);
    76                 if (selected_col.find(safe_col) == selected_col.end() || cost < selected_col[safe_col])
    77                     selected_col[safe_col] = cost;
    78             }
    79         }
    80     }
    81     cout << ans << endl;
    82     return 0;
    83 }
    View Code

    这份代码其实是有点问题的,如果中间采取插桩法,多次运行,safe[safe_index]的随机性可能会导致答案出错。(这是我改了下样例2得到的数据,某一次的运行结果)

    大神本身代码也是这样的,不信可以去看看。(但这并不改变人家是大神的事实)

    个人理解:每一行仅仅需要维护最左和最右两个宝藏。同时将小错误修正,得到一份相似代码。

     1 #include <bits/stdc++.h>
     2 
     3 #define maxn 200005
     4 #define mod 1000000007
     5 #define inf 0x3f3f3f3f3f3f3f3f
     6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     7 #define ll long long
     8 using namespace std;
     9 int maxx[maxn];
    10 int minn[maxn];
    11 vector<int> safe;
    12 
    13 signed main() {
    14     start;
    15     memset(minn, 0x3f, sizeof(minn));
    16     minn[1] = maxx[1] = 1;
    17     int n, m, k, q;
    18     cin >> n >> m >> k >> q;
    19     for (int i = 0; i < k; ++i) {
    20         int x, y;
    21         cin >> x >> y;
    22         maxx[x] = max(maxx[x], y);
    23         minn[x] = min(minn[x], y);
    24     }
    25     ++k;
    26     for (int i = 0; i < q; ++i) {
    27         int x;
    28         cin >> x;
    29         safe.push_back(x);
    30     }
    31     sort(safe.begin(), safe.end());
    32     map<ll, ll> selected_col;
    33     selected_col[1] = 0;
    34     ll ans;
    35     int current_row = 1;
    36     for (int row = 1; row <= n; ++row) {
    37         if (maxx[row] == 0)
    38             continue;
    39         ll l = minn[row], r = maxx[row];
    40         for (auto &it:selected_col)
    41             it.second += row - current_row;
    42         current_row = row;
    43         map<ll, ll> mint;
    44         mint[l] = mint[r] = inf;
    45         for (auto &it:selected_col) {
    46             mint[l] = min(mint[l], it.second + abs(it.first - r) + abs(l - r));
    47             mint[r] = min(mint[r], it.second + abs(it.first - l) + abs(r - l));
    48         }
    49         ans = min(mint[l], mint[r]);
    50         selected_col.clear();
    51         for (auto &it:mint) {
    52             int safe_index = lower_bound(safe.begin(), safe.end(), it.first) - safe.begin();
    53             if(safe_index!=safe.size()) {
    54                 int safe_col = safe[safe_index];
    55                 ll cost = it.second + abs(it.first - safe_col);
    56                 if (selected_col.find(safe_col) == selected_col.end() || cost < selected_col[safe_col])
    57                     selected_col[safe_col] = cost;
    58             }
    59             if (safe_index > 0) {
    60                 --safe_index;
    61                 int safe_col = safe[safe_index];
    62                 ll cost = it.second + abs(it.first - safe_col);
    63                 if (selected_col.find(safe_col) == selected_col.end() || cost < selected_col[safe_col])
    64                     selected_col[safe_col] = cost;
    65             }
    66         }
    67     }
    68     cout << ans << endl;
    69     return 0;
    70 }
    View Code

    (E和F本菜鸡肯定写不出)

    (如有问题,请在评论区和我说)

  • 相关阅读:
    破衣服的回忆
    underscorejs 源码走读笔记
    关于书籍《区块链以太坊DApp开发实战》的内容告示
    从区块链技术研发者的角度,说说我的区块链从业经历和对它的理解
    简介 以太坊 2.0 核心 之 共识机制的改变
    一般电商应用的订单队列架构思想
    详细讲解:零知识证明 之 ZCash 完整的匿名交易流程
    HyperLogLog 算法的原理讲解以及 Redis 是如何应用它的
    由 System.arraycopy 引发的巩固:对象引用 与 对象 的区别
    如何独立开发一个网络请求框架
  • 原文地址:https://www.cnblogs.com/F-Mu/p/11306615.html
Copyright © 2011-2022 走看看