链接: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 */
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 */
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 */
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 */
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 */