链接: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\n", 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\n", 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\n", 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\n", 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] = '\0';
 65             //printf("%d %s\n", 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\n", 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

 

posted on 2017-03-16 16:07  wkxnk  阅读(262)  评论(0编辑  收藏  举报