Problem:A(557A). Ilya and Diploma (贪心)
题目大意:
学校要举办运动会,有n个学生参加,为了鼓励学生主办方一共颁发n个证书,保证每人一本,有三种证书,每个证书都有一个颁发数目的区间,在满足上面的条件下,尽量A证书最多,B证书次之,C证书能多则多,问最后颁发三种证书各多少本?
解题思路:
先对三类证书分别颁发min本,还有学生没有证书的话,就对没有证书的同学按照A,B,C的顺序进行贪心。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int main () 4 { 5 int n; 6 while (scanf ("%d", &n) != EOF) 7 { 8 int a[3][2], num[3]; 9 for (int i=0; i<3; i++) 10 { 11 scanf ("%d %d", &a[i][0], &a[i][1]); 12 num[i] = a[i][0]; 13 a[i][1] -= a[i][0]; 14 n -= a[i][0]; 15 } 16 for (int i=0; i<3 && n>0; i++) 17 { 18 num[i] += min (n, a[i][1]); 19 n -= a[i][1]; 20 } 21 printf ("%d %d %d ", num[0], num[1], num[2]); 22 } 23 return 0; 24 }
Problem:B(557B). Pasha and Tea (sort)
题目大意:
有一壶开水Wml,现在有n个男生,n个女生,有2*n个杯子(杯子容量各不相同),要求在不溢出的情况下,给男生倒的水是女生的二倍,而且n个男生得到的水一样多,n个女生得到的水也一样多,问最多可以消耗多少ml水?
解题思路:
可以先对2*n个杯子的容量进行排序,女生肯定是用n个较小的杯子,男生用n个较大的杯子,因为男生,女生得到的水一样多,所以他们得到的水由他们所分到的杯子里面最小的决定,(PS:消耗的水不能比水壶的容量大)。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 200005; 4 int main () 5 { 6 int n; 7 double m, a[maxn]; 8 while (scanf ("%d %lf", &n, &m) != EOF) 9 { 10 for (int i=0; i<2*n; i++) 11 scanf ("%lf", &a[i]); 12 sort (a, a+2*n); 13 double num = min (a[0], a[n]/2) * 3 * n; 14 num = min (num, m); 15 printf ("%f ", num); 16 } 17 return 0; 18 }
Problem:C(557C). Arthur and Table (sort+模拟)
题目大意:
一个桌子有n条腿(八脚怪究极进化体),现在需要移除一些桌子腿使桌子变平稳(平稳是有一半以上的桌子腿的长度是未移除桌子腿中最长的),每移除一条桌子腿需要花费精力,问最少花费多少精力才能让桌子平稳?
解题思路:
先对所有的桌子腿按照按照长度升序排列,然后枚举每个出现过的长度作为使桌子平稳的桌子腿中最长的,求出所花费精力,比较得出最小。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100005; 4 const int N = 210; 5 struct Leg 6 { 7 int l, d; 8 }leg[maxn]; 9 bool cmp (Leg x, Leg y) 10 { 11 return x.l < y.l; 12 } 13 int main () 14 { 15 int n; 16 while (scanf ("%d", &n) != EOF) 17 { 18 int cnt[N], total = 0; 19 memset (leg, 0, sizeof(leg)); 20 memset (cnt, 0, sizeof(cnt)); 21 22 for (int i=0; i<n; i++) 23 scanf ("%d", &leg[i].l); 24 for (int i=0; i<n; i++) 25 { 26 scanf ("%d", &leg[i].d); 27 total += leg[i].d; 28 } 29 30 sort (leg, leg+n, cmp); 31 32 int Min, num, index, cost, i; 33 Min = total; 34 i = 0; 35 36 while (i < n) 37 { 38 index = i; 39 cost = total; 40 num = 0; 41 while (index<n && leg[i].l==leg[index].l) 42 {//枚举最高leg 43 cost -= leg[index++].d; 44 num ++; 45 } 46 num --; 47 for (int j=200; j>0&&num>0; j--) 48 {//加入低一点的leg,求出花费 49 cost -= min(num, cnt[j])*j; 50 num -= cnt[j]; 51 } 52 Min = min (Min, cost); 53 index = i; 54 while (index<n && leg[i].l==leg[index].l) 55 cnt[leg[index++].d] ++;//低一点的边加入cnt,以便后面枚举更高的leg时候减小花费 56 i = index; 57 } 58 printf ("%d ", Min); 59 } 60 return 0; 61 }
Problem:D(557D). Vitaly and Cycle (bfs+组合数)
题目大意:
由n个顶点和m条边组成的无向图(没有平行边,可能不连通),问最少加入几条边可以形成含有奇数个顶点的环,有几种加边的方法?
解题思路:
加边的条数一共有4情况(先用bfs对无向图进行染色处理,颜色为a的只能和颜色为b的相连):
1:不加边,无向图中含有奇环。
2:加一条边,无向图中还有有些点的度大于1,这些点所在的连通块里面假设颜色为a的点有x个,颜色为b的有y个,这个连通块里面有C(a,2)+C(b,2)中方法,连通块和连通块之间并不能通过加一条边形成奇环。
3:加两条边,无向图中点的度最多为一,若要形成奇环,就至少需要加两条边,方法数目为:m * C(n-2, 1);
4:加三条边,无向图中并没有边,只有n个点,就只能加三条边使得三个独立的点连成奇环,方法数目为:C(n, 3);
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef __int64 LL; 4 const int maxn = 100005; 5 struct Edge 6 { 7 int to, next; 8 }; 9 int head[maxn], cnt[maxn], tot; 10 LL ans; 11 Edge edge[maxn*2]; 12 void add (int from, int to) 13 {//邻接表存边 14 edge[tot].to = to; 15 edge[tot].next = head[from]; 16 head[from] = tot++; 17 } 18 int bfs (int s) 19 { 20 queue<int>Q; 21 int x, y, p, q, num, nu; 22 Q.push(s); 23 y = 0; 24 cnt[s] = x = 1; 25 while (!Q.empty()) 26 { 27 p = Q.front(); 28 Q.pop(); 29 nu = cnt[p] + 1;//cnt[i]为奇数,i点为red,否则i点为black 30 num = head[p]; 31 while (num != -1) 32 { 33 q = edge[num].to; 34 if (cnt[q] == -1)//未染色 35 { 36 Q.push(q); 37 if (nu % 2)//统计为red,black颜色点的数目 38 x++; 39 else 40 y ++; 41 cnt[q] = nu; 42 } 43 else if (cnt[q]%2 == cnt[p]%2)//遇到奇环 44 return 1; 45 num = edge[num].next; 46 } 47 } 48 ans += (LL)x * (x-1) / 2;//没遇到奇环,计算加一条边的方法数目 49 ans += (LL)y * (y-1) / 2; 50 return 0; 51 } 52 int main () 53 { 54 int n, m; 55 scanf ("%d %d", &n, &m); 56 if (m == 0) 57 {//加三条边 58 printf ("3 %I64d ", (LL)n*(n-1)*(n-2)/6); 59 return 0; 60 } 61 memset (edge, -1, sizeof(edge)); 62 memset (head, -1, sizeof(head)); 63 memset (cnt, 0, sizeof(cnt)); 64 tot = ans = 0; 65 for (int i=0; i<m; i++) 66 { 67 int from, to; 68 scanf ("%d %d", &from, &to); 69 add (from, to); 70 add (to, from); 71 cnt[from] ++; 72 cnt[to] ++; 73 } 74 int Max = -1; 75 for (int i=1; i<=n; i++) 76 Max = max(Max, cnt[i]); 77 if (Max == 1) 78 {//加两条边 79 printf ("2 %I64d ", (LL)m * (n-2)); 80 return 0; 81 } 82 memset (cnt, -1, sizeof(cnt)); 83 for (int i=1; i<=n; i++) 84 { 85 if (cnt[i] == -1) 86 { 87 int res = bfs(i); 88 if (res) 89 { 90 printf ("0 1 "); 91 return 0; 92 } 93 } 94 } 95 printf ("1 %I64d ", ans); 96 return 0; 97 }