zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营 第六场

    题目链接:https://ac.nowcoder.com/acm/contest/886#question


    A:

    光速签到。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson (curpos<<1)
    15 #define rson (curpos<<1|1)
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 int t;
    21 const int maxn = 2e3 + 10;
    22 
    23 int main() {
    24     scanf("%d", &t);
    25     for (int ca = 1; ca <= t; ca++) {
    26         printf("Case #%d: ", ca);
    27         char s[maxn], t[27];
    28         scanf("%s", s + 1);
    29         scanf("%s", t + 1);
    30         map<char, int>m; m.clear();
    31         int len = strlen(s + 1), dry = 0, wet = 0, harm = 0;
    32         for (int i = 1; i <= len; i++)
    33                 if (!m.count(s[i])) m[s[i]] = 1; else m[s[i]]++;
    34         for (int i = 1; i <= 26; i++) {
    35             if (t[i] == 'd') dry += m[(char)(i + 'a' - 1)];
    36             else if (t[i] == 'w') wet += m[(char)(i + 'a' - 1)];
    37             else if (t[i] == 'h') harm += m[(char)(i + 'a' - 1)];
    38         }
    39         if (harm * 4 >= len) puts("Harmful");
    40         else if (harm * 10 <= len) puts("Recyclable");
    41         else if (!wet || dry / wet >= 2) puts("Dry");
    42         else puts("Wet");
    43     }
    44     return 0;
    45 }
    View Code

    B:

    一开始认为可以直接找最长的最靠后的0串进行压缩,后来发现有个大坑:首尾和中间同样长度的0对答案贡献不一样大。在中间的连续0压缩后能少1长度。

    可以直接枚举删去哪一段0再计算答案,保证正确。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson (curpos<<1)
    15 #define rson (curpos<<1|1)
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 10;
    21 int a[maxn];
    22 
    23 int main() {
    24     int t; scanf("%d", &t);
    25     for (int caseNum = 1; caseNum <= t; caseNum++) {
    26         int startPos = 0, maxLen = 0, currLen = 0;
    27         for (int i = 1; i <= 8; i++) {
    28             a[i] = 0;
    29             for (int j = 1; j <= 16; j++) {
    30                 int x; scanf("%1d", &x);
    31                 a[i] = a[i] * 2 + x;
    32             }
    33             if (!a[i]) currLen++; // currLen记录当前连续的全0段个数
    34             else { // 如果遇到全1段,维护答案
    35                 if (currLen >= maxLen && currLen > 1) {
    36                     startPos = i - currLen;
    37                     maxLen = currLen;
    38                 }
    39                 currLen = 0;
    40             }
    41             if (i == 8 && currLen > 1) { // 如果全0段延续到末尾
    42                 if (currLen > maxLen) // 如果是最长,照常处理
    43                     startPos = i - currLen + 1, maxLen = currLen;
    44                 if (currLen == maxLen && startPos == 1) // 否则判断开头有长度跟最大长度相同的全0段
    45                     startPos = i - currLen + 1;
    46             }
    47         }
    48         printf("Case #%d: ", caseNum);
    49         if (startPos == 1) printf(":");
    50         for (int i = 1; i <= 8; i++) {
    51             if (i == startPos) {
    52                 printf(":"); i += maxLen;
    53             }
    54             if (i > 8) puts("");
    55             else printf("%x%c", a[i], ":
    "[i == 8]);
    56         }
    57     }
    58     return 0;
    59 }
    View Code

    D:

    这道题很容易想到二分箱子容积,然后就错了。因为这个题箱子容积跟答案没有单调性!

    为了保证正确性,这个题最好的方法就是枚举答案。答案下界显然是max(max(vi),sumV/k),上界则为sumV/k+max(vi),这样容积的箱子一定能放下所有东西。然后再逐个物品check一次就好了。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson (curpos<<1)
    15 #define rson (curpos<<1|1)
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 1e3 + 10;
    21 int v[maxn], puted[maxn];
    22 
    23 int main() {
    24     int t; scanf("%d", &t);
    25     for (int caseNum = 1; caseNum <= t; caseNum++) {
    26         int n, k, sum = 0; scanf("%d%d", &n, &k);
    27         for (int i = 1; i <= n; i++) {
    28             scanf("%d", &v[i]); sum += v[i];
    29         }
    30         sot(v, n);
    31         int limV = max(v[n], sum / k);
    32         for (int curV = limV;; curV++) {
    33             for (int i = 1; i <= n; i++) puted[i] = 0;
    34             int cnt = 0;
    35             for (int i = 1; i <= k; i++) {
    36                 int tmpV = curV;
    37                 for (int j = n; j > 0; j--) {
    38                     if (!puted[j] && v[j] <= tmpV) {
    39                         puted[j] = 1;
    40                         tmpV -= v[j];
    41                         cnt++;
    42                     }
    43                 }
    44             } if (cnt == n) {
    45                 printf("Case #%d: %d
    ", caseNum, curV);
    46                 break;
    47             }
    48         }
    49     }
    50 }
    View Code

    G:

    一看就是蔡勒公式相关题。通过一些简单性质可以进行剪枝:日份第一位只能是0123,月份第一位只能是0和1,年份第一位不可能为0。而且合法日期+星期五的限制很紧,题解里谈到对于任何一个加密后的日期,只有几万个排列能将其映射到合法日期。故可只对前弱冠个日期求出所有合法的排列之后,再依次检查是否对所有日期合法。注意要对重复日期去重。

    顺便这里补充一下蔡勒公式

    对于1752年9月3日前的日期,ans = (d+2*m+3*(m+1)/5+y+y/4+5) % 7;而对于1752年9月3日后的日期,ans = (d + 2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7。这是因为罗马教皇决定在1582年10月4日后使用格利戈里历法,而英国则是在1752年9月3日后才接受使用格利戈里历法。要注意这个点。

    计算出来的答案从0到6分别为星期日到星期六。使用时要注意,对于1月和2月的日期,要变为上一年的13月和14月参与计算。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson (curpos<<1)
    15 #define rson (curpos<<1|1)
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 int a[15], mon[15] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    21 const int maxn = 1e5 + 10;
    22 string s[maxn];
    23 
    24 int check(int x) {
    25     int year = 0, month = a[s[x][5] - 'A'] * 10 + a[s[x][6] - 'A'], day = a[s[x][8] - 'A'] * 10 + a[s[x][9] - 'A'];
    26     for (int i = 0; i < 4; i++)
    27         year = year * 10 + a[s[x][i] - 'A'];
    28     if (year % 4 == 0 && year % 100 || year % 400 == 0) mon[2] = 29;
    29     else mon[2] = 28;
    30     if (year < 1600 || year > 9999 || month < 1 || month > 12 || day < 1 || day > mon[month])
    31         return 0;
    32     if (month <= 2) month += 12, year--;
    33     int ans = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400 + 1) % 7;
    34     if (ans == 5) return true;
    35     else return false;
    36 }
    37 
    38 int main() {
    39     int t; scanf("%d", &t);
    40     for (int caseNum = 1; caseNum <= t; caseNum++) {
    41         printf("Case #%d: ", caseNum);
    42         for (int i = 0; i < 10; i++) a[i] = i;
    43         int n; scanf("%d", &n);
    44         for (int i = 1; i <= n; i++) cin >> s[i];
    45         sot(s, n);
    46         n = unique(s + 1, s + 1 + n) - s - 1;
    47         int tmp = min(n, 20), flag = 1;
    48         do {
    49             int haveSolution = 1;
    50             for (int i = 1; haveSolution && i <= tmp; i++)
    51                 if (!check(i)) haveSolution = 0;
    52             if (haveSolution)
    53                 for (int i = tmp + 1; haveSolution && i <= n; i++)
    54                     if (!check(i)) haveSolution = 0;
    55             if (haveSolution) {
    56                 for (int i = 0; i < 10; i++) printf("%d", a[i]);
    57                 puts("");
    58                 flag = 0;
    59                 break;
    60             }
    61         } while (next_permutation(a, a + 10));
    62         if (flag) puts("Impossible");
    63     }
    64     return 0;
    65 }
    View Code

    J:

    一个人有n个技能,每个技能最高可以升到m级。初始状态下n个技能的等级都是0级。第i个技能从(j-1)级升到j级要花费cij点代价(有可能是负数)。如果所有技能都达到了j级,就可以获得dj点代价(有可能是负数)。输出这个人能获得的最大代价是多少。

    这个题很容易想到贪心,然后就踩坑了:枚举有j个等级升满,然后对第i种技能从pre[i][j]到pre[i][m]中选择最小的那个作为第i种等级的最终等级。pre[i][j]表示第i种技能升j级所需代价和。这种做法的问题在于d[j]可能是负的,贪心选最小的pre可能导致j+1之后某些负的level使得答案变小。可以这样修正得到正解:枚举一种等级i作为level最低的技能,并枚举它的等级j,那么其他技能的等级可以在j到m之间任取。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson (curpos<<1)
    15 #define rson (curpos<<1|1)
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 1e3 + 10;
    21 ll c[maxn][maxn], d[maxn], sum[maxn], val[maxn], tem[maxn];
    22 int n, m;
    23 
    24 int pos(ll *c, int l, int r) {
    25     ll val = ll_inf; int minI;
    26     for (int i = l; i <= r; i++)
    27         if (c[i] <= val) {
    28             val = c[i];
    29             minI = i;
    30         }
    31     return minI;
    32 }
    33 
    34 int main() {
    35     int t; scanf("%d", &t);
    36     for (int casenum = 1; casenum <= t; casenum++) {
    37         scanf("%d%d", &n, &m);
    38         for (int i = 1; i <= n; i++) sum[i] = 0;
    39         for (int i = 1; i <= n; i++) {
    40             c[i][0] = 0; val[i] = ll_inf;
    41             for (int j = 1; j <= m; j++) {
    42                 scanf("%lld", &c[i][j]);
    43                 sum[j] += c[i][j];
    44                 c[i][j] += c[i][j - 1];
    45                 if (c[i][j] <= val[i]) {
    46                     val[i] = c[i][j];
    47                     tem[i] = j;
    48                 }
    49             }
    50         }
    51         d[0] = 0;
    52         for (int i = 1; i <= m; i++) {
    53             scanf("%lld", &d[i]);
    54             d[i] -= sum[i]; d[i] += d[i - 1];
    55         }
    56         ll ans = 0, tmp, maxv;
    57         for (int i = 0; i <= m; i++) {
    58             tmp = d[i]; int cnt = 0;
    59             if (i != m) {
    60                 ll minv; maxv = -ll_inf;
    61                 for (int j = 1; j <= n; j++) {
    62                     if (tem[j] <= i) tem[j] = pos(c[j], i + 1, m);
    63                     minv = c[j][tem[j]];
    64                     if (minv - c[j][i] < 0) {
    65                         maxv = max(maxv, minv - c[j][i]);
    66                         tmp -= minv - c[j][i];
    67                         cnt++;
    68                     }
    69                 }
    70             }
    71             if (cnt == n) tmp += maxv;
    72             ans = max(ans, tmp);
    73         }
    74         printf("Case #%d: %lld
    ", casenum, ans);
    75     }
    76     return 0;
    77 }
    View Code

    也可以这样做:显然升级过程没有后效性,考虑dp。设dp[i][j]为前i种科技最小等级为j时,所付出的最小代价。

    状态转移方程dp[i+1][j]=min(dp[i][k]+pre[i+1][u]),其中k>=j,u>=j,且k和u至少有一个为j。

     1 /* basic header */
     2 #include <bits/stdc++.h>
     3 /* define */
     4 #define ll long long
     5 #define dou double
     6 #define pb emplace_back
     7 #define mp make_pair
     8 #define sot(a,b) sort(a+1,a+1+b)
     9 #define rep1(i,a,b) for(int i=a;i<=b;++i)
    10 #define rep0(i,a,b) for(int i=a;i<b;++i)
    11 #define eps 1e-8
    12 #define int_inf 0x3f3f3f3f
    13 #define ll_inf 0x7f7f7f7f7f7f7f7f
    14 #define lson (curpos<<1)
    15 #define rson (curpos<<1|1)
    16 /* namespace */
    17 using namespace std;
    18 /* header end */
    19 
    20 const int maxn = 2e3 + 10;
    21 ll a[maxn][maxn], sum[maxn], dp[maxn][maxn][20];
    22 int n, m;
    23 
    24 void init() {
    25     for (int i = 1; i <= n; i++)
    26         for (int j = 1; j <= m + 1; j++)
    27             dp[i][j][0] = a[i][j];
    28     for (int k = 1; k <= n; k++)
    29         for (int j = 1; (1 << j) <= m + 1; j++)
    30             for (int i = 1; i + (1 << j) - 1 <= m + 1; i++)
    31                 dp[i][k][j] = min(dp[i][k][j - 1], dp[i][k + (1 << j - 1)][j - 1]);
    32 }
    33 
    34 ll rmq(int j, int l, int r) {
    35     int k = log2(r - l + 1);
    36     return min(dp[j][l][k], dp[j][r - (1 << k) + 1][k]);
    37 }
    38 
    39 int main() {
    40     int t; scanf("%d", &t);
    41     for (int caseNum = 1; caseNum <= t; caseNum++) {
    42         scanf("%d%d", &n, &m);
    43         for (int i = 1; i <= n; i++)
    44             for (int j = 2; j <= m + 1; j++) {
    45                 scanf("%lld", &a[i][j]); // 同一技能升级代价做前缀和
    46                 a[i][j] += a[i][j - 1];
    47             }
    48         init();
    49         for (int i = 2; i <= m + 1; i++) {
    50             scanf("%lld", &sum[i]); // 技能最低等级奖励也做前缀和
    51             sum[i] += sum[i - 1];
    52         }
    53         ll ans = 0;
    54         for (int j = 1; j <= m + 1; j++) {
    55             ll tmp1 = 0;
    56             for (int i = 1; i <= n; i++) tmp1 += rmq(i, j, m + 1);
    57             for (int i = 1; i <= n; i++) {
    58                 ll tmp = tmp1;
    59                 tmp -= rmq(i, j, m + 1); tmp += a[i][j];
    60                 tmp = sum[j] - tmp; ans = max(ans, tmp);
    61             }
    62         }
    63         printf("Case #%d: %lld
    ", caseNum, ans);
    64     }
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    【css】 text-align 居中导航
    css
    css
    css
    css : object-fit 兼容 ie 的解决方案
    Linux下Nginx配置多个站点
    Dart之环境搭建
    酒店行业的OTA
    主流消息队列MQ比较,MQ的4类应用场景
    消息队列Kafka、RocketMQ、RabbitMQ的优劣势比较
  • 原文地址:https://www.cnblogs.com/JHSeng/p/11296837.html
Copyright © 2011-2022 走看看