Codeforces Round #311 (Div. 2)

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 }
本文为博主原创文章,未经博主允许不得转载。
原文地址:https://www.cnblogs.com/alihenaixiao/p/4613929.html