• Codeforces Round #402 (Div. 2)


    链接:http://codeforces.com/contest/779

    A. Pupils Redistribution

    题意:某中学有A、B两组学生,且每组都有n个人。每个学生的学术指数是已知的,是从1到5之间的某个正整数。A、B两组学生的学术指数分别是 a1, a2, ..., an 和

    b1, b2, ..., bn。现在想在两组之间交换学生,问最少经过几次交换,可以使所有拥有同一个学术指数的两组学生数量相等,如果做不到,则输出-1。

    分析:对于每一个学术指数Xi (1<=Xi<=5),统计每组学生人数,作出两组数量之差再除以2得到 Di ,如果 ∑ Di = 0 说明可实现,( ∑ | Di | ) / 2 则是需交换的次数,如果

    ∑ Di ≠ 0,说明不可实现,输出 -1 即可。

    代码:

     1 #include<stdio.h>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 int cnt1[10], cnt2[10];
     6 
     7 int main()
     8 {
     9     int n;
    10     while(~scanf("%d", &n))
    11     {
    12         for(int i = 1; i <= 5; ++i)
    13             cnt1[i] = 0, cnt2[i] = 0;
    14         int x;
    15         for(int i = 0; i < n; ++i)
    16         {
    17             scanf("%d", &x);
    18             ++cnt1[x];
    19         }
    20         for(int i = 0; i < n; ++i)
    21         {
    22             scanf("%d", &x);
    23             ++cnt2[x];
    24         }
    25 
    26         bool sign = true;
    27         for(int i = 1; i <= 5; ++i)
    28         if((cnt1[i] - cnt2[i]) % 2)
    29         {
    30             sign = false;
    31             break;
    32         }
    33         if(!sign)
    34         {
    35             puts("-1");
    36             continue;
    37         }
    38 
    39 //        for(int i = 1; i <= 5; ++i)
    40 //            printf("%d %d
    ", cnt1[i], cnt2[i]);//
    41 
    42         int flag = 0, ans = 0, temp;
    43         for(int i = 1; i <= 5; ++i)
    44         {
    45                 temp = (cnt1[i] - cnt2[i]) / 2;
    46                 flag += temp;
    47                 if(temp > 0) ans += temp;
    48                 else ans -= temp;
    49         }
    50 
    51         if(!flag) printf("%d
    ", ans / 2);
    52         else puts("-1");
    53     }
    54     return 0;
    55 }
    56 
    57 /*
    58 4
    59 5 4 4 4
    60 5 5 4 5
    61 
    62 6
    63 1 1 1 1 1 1
    64 5 5 5 5 5 5
    65 
    66 1
    67 5
    68 3
    69 
    70 9
    71 3 2 5 5 2 3 3 3 2
    72 4 1 4 1 1 2 4 4 1
    73 
    74 5
    75 1 2 3 4 5
    76 1 2 3 4 5
    77 */
    View Code

    B. Weird Rounding

    题意:给你一个数 n 和数 k,你可以去掉数 n 中的一些位数,使它能被 10 ^ k 整除,问你最少去掉几位可以实现。(1. 题目保证有解 2. 规定前导零为不合法形式)

    分析:从后面位数开始,遇到非零的位数直接去掉,直到最后连续的为零的位数达到 k 位为止,则此时已去掉的位数就是最少的。如果还未达到 k 位,数 n 的位数已经到头,

    没有位数可去了,则说明前面这个策略失效,唯一的办法是将数 n 所有位数全部去掉,只保留一个 0。

    代码:

     1 #include<stdio.h>
     2 using namespace std;
     3 
     4 int dig[10];
     5 
     6 int main()
     7 {
     8     int n, k;
     9     while(~scanf("%d%d", &n, &k))
    10     {
    11         if(!n)
    12         {
    13             puts("0");
    14             continue;
    15         }
    16 
    17         int p = 0;
    18         while(n)
    19         {
    20             dig[p++] = n % 10;
    21             n /= 10;
    22         }
    23 
    24         int i, ans = 0, cnt = 0;
    25         for(i = 0; i < p && cnt < k; ++i)
    26         {
    27             if(dig[i]) ++ans;
    28             else ++cnt;
    29         }
    30         if(i == p && cnt < k)
    31         ans = p - 1;
    32 
    33         printf("%d
    ", ans);
    34     }
    35     return 0;
    36 }
    37 
    38 /*
    39 30020 3
    40 
    41 100 9
    42 
    43 10203049 2
    44 */
    View Code

    C. Dishonest Sellers

    题意:某人去一个商店买东西,他总共需要买 n 件东西,已知这 n 件东西目前的价格分别是 a1, a2, ..., an。然而,商店一周后要降价促销,这 n 件东西的价格将变成 b1, b2, ..., bn。

    然而,这个商店比较鸡贼,说是降价促销,其实某些商品反而是涨价的,也就是说,bi 不保证小于 ai (1 <= i <= n)。但是这个人比较心急,他必须现在就买至少 k 件东西,然后剩下

    其余的东西可以等到一周后再买。问他要买这 k 件东西的最小花费。

    分析:作出促销前后的价差 Di, 按从大到小排序,Di >= 0 表示现在买是赚的(或者是不赚不赔的),将来买是亏的(或者是不赚不赔的);Di < 0 表示现在买是亏的,将来买是赚的。

    如果 Di >= 0 的项(即非负项)多于或等于 k,那么现在可以把这些非负项都买走,反之,如果非负项少于 k,则不得不现在买走一些负项。既然这些 Di 是降序排列的,那么即使买走

    一些负项,也是损失最小的方案。

    代码:

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 struct item
     6 {
     7     int a, b, d;
     8 } t[220000];
     9 
    10 bool cmp(item x, item y)
    11 {
    12     return x.d > y.d;
    13 }
    14 
    15 int main()
    16 {
    17     int n, k;
    18     while(~scanf("%d%d", &n, &k))
    19     {
    20         for(int i = 0; i < n; ++i)
    21             scanf("%d", &t[i].a);
    22         for(int i = 0; i < n; ++i)
    23             scanf("%d", &t[i].b);
    24         for(int i = 0; i < n; ++i)
    25             t[i].d = t[i].b - t[i].a;
    26         sort(t, t + n, cmp);
    27 
    28         int p = 0, ans = 0;
    29         while(t[p].d >= 0 && p < n) ++p;
    30         if(p < k)
    31         {
    32         for(int i = 0; i < k; ++i)
    33             ans += t[i].a;
    34         for(int i = k; i < n; ++i)
    35             ans += t[i].b;
    36         }
    37         else
    38         {
    39         for(int i = 0; i < p; ++i)
    40             ans += t[i].a;
    41         for(int i = p; i < n; ++i)
    42             ans += t[i].b;
    43         }
    44 
    45         printf("%d
    ", ans);
    46     }
    47     return 0;
    48 }
    49 
    50 /*
    51 3 1
    52 5 4 6
    53 3 1 5
    54 
    55 5 3
    56 3 4 7 10 3
    57 4 5 5 12 5
    58 
    59 1 1
    60 1
    61 1
    62 
    63 1 0
    64 1
    65 1
    66 */
    View Code

    D. String Game

    题意:给你一个长串 t 和一个短串 p, 给定一个下标序列,你必须按照这个序列依次删除 t 中的对应下标的字符,直至串 t 为空串(删除过程中,下标标号不变)。问在保证串 p 是串 t

    的子序列的情况下,最多可以删除多少个字符?

    分析:注意到如果多删除字符的 t 是 p 的母串,那么少删除字符的 t 一定能保证是 p 的母串。因此可以对删除序列进行二分,找到恰好使 t 变成非母串的删除字符的位置。注意,二分完

    成时,需要对 mid 所在的位置进行讨论,因为 mid 既可能是最后一个 t 为母串的位置,也可能是第一个 t 为非母串的位置。

    代码:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<algorithm>
      4 #include<vector>
      5 using namespace std;
      6 
      7 const int N = 220000;
      8 int a[N];
      9 int next[N], S[N], T[N];
     10 bool sig[N];
     11 char t[N], t1[N], p[N];
     12 int c[N], d[N];
     13 vector<int> location[30];
     14 
     15 bool Find(char* a, int l1, char* b, int l2)
     16 {
     17     int i = 0, j = 0;
     18     bool sign = true;
     19      while(j < l2)
     20      {
     21          if(!sign) break;
     22         while(a[i] != b[j])
     23         {
     24             ++i;
     25             if(i >= l1)
     26             {
     27                 sign = false;
     28                 break;
     29             }
     30         }
     31 
     32         ++i, ++j;
     33     }
     34 
     35     return sign;
     36     //return !(i >= l1 && j < l2);
     37 }
     38 
     39 int main()
     40 {
     41     while(~scanf("%s%s", t, p))
     42     {
     43         int l1 = strlen(t);
     44         int l2 = strlen(p);
     45         for(int i = 0; i < l1; ++i)
     46         {
     47             scanf("%d", &a[i]);
     48             a[i] -= 1;
     49         }
     50 
     51         int l = 0, r = l1 - 1, mid;
     52         bool flag;
     53         while(l <= r)
     54         {
     55             mid = l + r >> 1;
     56             memset(sig, false, sizeof sig);
     57             for(int i = 0; i <= mid; ++i)
     58                 sig[a[i]] = true;
     59 
     60             int k = 0;
     61             for(int i = 0; i < l1; ++i)
     62                 if(!sig[i])
     63                 t1[k++] = t[i];
     64             t1[k] = '';
     65             //printf("%d %s
    ", mid, t1);//
     66 
     67             flag = Find(t1, k, p, l2);
     68             if(flag) l = mid + 1;
     69             else r = mid - 1;
     70         }
     71         printf("%d
    ", flag? mid + 1: mid);
     72     }
     73     return 0;
     74 }
     75 
     76 /*
     77 ababcba
     78 abb
     79 5 3 4 1 7 6 2
     80 3
     81 
     82 bbbabb
     83 bb
     84 1 6 3 4 2 5
     85 4
     86 
     87 aa
     88 a
     89 1 2
     90 1
     91 
     92 ab
     93 a
     94 1 2
     95 0
     96 
     97 ab
     98 a
     99 2 1
    100 1
    101 */
    View Code

    E. Bitwise Formula

    题意:给你一个数 n,一个数 m,然后 n 行,每行定义一个变量,有的变量直接被赋值为一个 m 位的二进制数,有的变量由前面的变量或者用 ”?“ 经过AND,OR,XOR三种位运算得出。

    现在要你给变量 ”?“ 赋值(只能是 m 位二进制数),使这 n 个变量的和最大或最小,并输出相应的这个 m 位二进制数。

    分析:注意到对于所有变量,其每一个二进制位的运算是相互独立的,因此对于每一位,对每个变量而言,如果能得出尽可能多的 ”1“ ,则这一位相加的和是最大的,反之,得出尽可能少

    的 ”1“ ,则这一位相加的和是最小的。

    代码:

      1 #include<stdio.h>
      2 #include<string>
      3 #include<map>
      4 #include<algorithm>
      5 #include<iostream>
      6 using namespace std;
      7 
      8 const int N = 5500;
      9 const int M = 1100;
     10 
     11 string s1, s2, s3;
     12 int val[N];
     13 int n, m, top;
     14 int ans1[M], ans2[M];
     15 map<string, int> ID;
     16 int idcnt;
     17 
     18 struct data
     19 {
     20     int x, y, z;
     21     string w, op;
     22     int t;
     23 } a[N];
     24 
     25 //bool isdigit(char ch)
     26 //{
     27 //    return ('0' <= ch && ch <= '9');
     28 //}
     29 
     30 int code(string s)
     31 {
     32     if(s == "?") return 0;
     33     if(!ID.count(s)) ID[s] = ++idcnt;
     34     return ID[s];
     35 }
     36 
     37 int work(int bit, int x)
     38 {
     39     int res = 0;
     40     val[0] = x;
     41     for(int i = 0; i < n; ++i)
     42     {
     43         int k = a[i].x;
     44         if(a[i].t == 0)
     45         {
     46             val[k] = a[i].w[bit] - '0';
     47         }
     48         else
     49         {
     50             switch(a[i].op[0])
     51             {
     52             case 'A':
     53                 val[k] = val[a[i].y] & val[a[i].z];
     54                 break;
     55             case 'O':
     56                 val[k] = val[a[i].y] | val[a[i].z];
     57                 break;
     58             case 'X':
     59                 val[k] = val[a[i].y] ^ val[a[i].z];
     60                 break;
     61             }
     62         }
     63         res += val[k];
     64     }
     65     return res;
     66 }
     67 
     68 int main()
     69 {
     70     while(cin >> n >> m)
     71     {
     72         for(int i = 0; i < n; ++i)
     73         {
     74             cin >> s1 >> s2;
     75             a[i].x = code(s1);
     76             cin >> s1;
     77             if(isdigit(s1[0]))
     78             {
     79                 a[i].t = 0;
     80                 a[i].w = s1;
     81                 continue;
     82             }
     83             cin >> s2 >> s3;
     84             a[i].y = code(s1), a[i].op = s2;
     85             a[i].z = code(s3), a[i].t = 1;
     86         }
     87 
     88         for(int i = 0; i < m; ++i)
     89         {
     90             int t1 = work(i, 0), t2 = work(i, 1);
     91             if(t1 < t2) ans1[i] = 0, ans2[i] = 1;
     92             else if(t1 > t2) ans1[i] = 1, ans2[i] = 0;
     93             else ans1[i] = ans2[i] = 0;
     94         }
     95 
     96         for(int i = 0; i < m; ++i) cout << ans1[i];
     97         cout << endl;
     98         for(int i = 0; i < m; ++i) cout << ans2[i];
     99         cout << endl;
    100     }
    101     return 0;
    102 }
    103 
    104 /*
    105 3 3
    106 a := 101
    107 b := 011
    108 c := ? XOR b
    109 
    110 5 1
    111 a := 1
    112 bb := 0
    113 cx := ? OR a
    114 d := ? XOR ?
    115 e := d AND bb
    116 */
    View Code
  • 相关阅读:
    【Linux】ZeroMQ 在 centos下的安装
    ZeroMQ下载、编译和使用
    在Linux系统上安装Git
    Linux下python2.7安装pip
    [Tyvj1474]打鼹鼠
    [BZOJ2908]又是nand
    [SPOJ375]Qtree
    浅谈算法——树链剖分
    [BZOJ5368/Pkusc2018]真实排名
    [FJOI2007]轮状病毒
  • 原文地址:https://www.cnblogs.com/qiucz/p/6559696.html
Copyright © 2020-2023  润新知