2018百度之星初赛B - A,D,F

Posted wangrunhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018百度之星初赛B - A,D,F相关的知识,希望对你有一定的参考价值。

总结:这一次的百度之星之行到这里也就结束了,充分的认识到了自己的不足啊。。。果然还是做的题太少,,见识的题型也还太少,对于STL的掌握还是不够到位啊!!(STL大法是真的好,建议大家认认真真的好好学学),这一次在一群大佬中被狂虐,下来之后还是继续刷题吧,希望明年继续加油!!!(共勉,加油!)

A. degree

Problem Description

度度熊最近似乎在研究图论。给定一个有 NN 个点 (vertex) 以及 MM 条边 (edge) 的无向简单图 (undirected simple graph),此图中保证没有任何圈 (cycle) 存在。

现在你可以对此图依序进行以下的操作:

  1. 移除至多 KK 条边。
  2. 在保持此图是没有圈的无向简单图的条件下,自由的添加边至此图中。

请问最后此图中度数 (degree) 最大的点的度数可以多大呢?

Input

输入的第一行有一个正整数 TT,代表接下来有几笔测试资料。

对于每笔测试资料: 第一行有三个整数 NN, MM, KK。 接下来的 MM 行每行有两个整数 aa 及 bb,代表点 aa 及 bb 之间有一条边。 点的编号由 00 开始至 N - 1N1。

  • 0 le K le M le 2 imes 10^50KM2×10?5??
  • 1 le N le 2 imes 10^51N2×10?5??
  • 0 le a, b < N0a,b<N
  • 给定的图保证是没有圈的简单图
  • 1 le T le 231T23
  • 至多 22 笔测试资料中的 N > 1000N>1000
Output

对于每一笔测试资料,请依序各自在一行内输出一个整数,代表按照规定操作后可能出现的最大度数。

Sample Input
2
3 1 1
1 2
8 6 0
1 2
3 1
5 6
4 1
6 4
7 0
Sample Output
2
4

思路:以当前度最多的点为计算点,设当前最多的度为a,判断当前的孤立节点 cnt 有多少个即可以直接加入结果!
   其次看与该点不相连的边 b 有几条;因为去掉与之不相连的k条边即可以加上k个度,不过此处去掉的边有一定
   的上限limit = ( m - a );所以ans = a + cnt + min ( k , limit ).


 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 #include<set>
 6 using namespace std;
 7 const int maxn = 2e5 + 10;
 8 vector<int>e[maxn];
 9 int n, m, k, T;
10 int x[maxn], cnt, vis[maxn];
11 void dfs(int s)
12 {
13     for (int i = 0; i<e[s].size(); i++) {
14         if (!vis[e[s][i]]) {
15             vis[e[s][i]] = cnt;
16             dfs(e[s][i]);
17         }
18     }
19 }
20 int main()
21 {
22     ios::sync_with_stdio(false);
23     cin >> T;
24     while (T--) {
25         for (int i = 0; i <= n; i++)
26             e[i].clear();
27         memset(vis, 0, sizeof(vis));
28         memset(x, 0, sizeof(x));
29         cin >> n >> m >> k;
30         int a, b;
31         for (int i = 0; i<m; i++) {
32             cin >> a >> b;
33             a++, b++;
34             x[a]++; x[b]++;
35             e[a].push_back(b);
36             e[b].push_back(a);
37         }
38         cnt = 1; int ma = 0;
39         for (int i = 1; i <= n; i++) {
40             if (ma<x[i])ma = x[i];
41             if (!vis[i]) {
42                 dfs(i);
43                 cnt++;
44             }
45         }
46         cnt--;//当前的联通块数量 
47         int count = m - ma;//代表最多可以删除多少条边
48         cnt -= 1;//除了那一块度最多的之外的联通快数量
49         int ans = cnt + min(count, k) + ma;//答案等于孤立点的数量+当前的度数+最多可以去掉几条边(即可以再加入几条边)
50         cout << ans << endl;
51     }
52     return 0;
53 }

 

 

D.p1m2

Problem Description

度度熊很喜欢数组!!

我们称一个整数数组为稳定的,若且唯若其同时符合以下两个条件:

  1. 数组里面的元素都是非负整数。
  2. 数组里面最大的元素跟最小的元素的差值不超过 11。

举例而言,[1, 2, 1, 2][1,2,1,2] 是稳定的,而 [-1, 0, -1][1,0,1] 跟 [1, 2, 3][1,2,3] 都不是。

现在,定义一个在整数数组进行的操作:

  • 选择数组中两个不同的元素 aa 以及 bb,将 aa 减去 22,以及将 bb 加上 11。

举例而言,[1, 2, 3][1,2,3] 经过一次操作后,有可能变为 [-1, 2, 4][1,2,4] 或 [2, 2, 1][2,2,1]。

现在给定一个整数数组,在任意进行操作后,请问在所有可能达到的稳定数组中,拥有最大的『数组中的最小值』的那些数组,此值是多少呢?

Input

输入的第一行有一个正整数 TT,代表接下来有几组测试数据。

对于每组测试数据: 第一行有一个正整数 NN。 接下来的一行有 NN 个非负整数 x_ix?i??,代表给定的数组。

  • 1 le N le 3 imes 10^51N3×10?5??
  • 0 le x_i le 10^80x?i??10?8??
  • 1 le T le 181T18
  • 至多 11 组测试数据中的 N > 30000N>30000
Output

对于每一组测试数据,请依序各自在一行内输出一个整数,代表可能到达的平衡状态中最大的『数组中的最小值』,如果无法达成平衡状态,则输出 -11。

Sample Input
2
3
1 2 4
2
0 100000000

Sample Output
2
33333333

思路:二分,直接对这个最大值二分,对每一次二分的结果,统计原数组中比之大的数中能够减去的2的个数f2 与比之小能加的1的个数f1,若f2>=f1则代表此结果是成立的,可以往大递归;
   (至于为什么是成立的可以动手模拟一下)否则必须往小递归,最后输出结果即可.(由于题目说每个xi都是大于等于零,所以对于每组数据必定会存在一个解)

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 typedef long long LL;
 6 const int maxn = 3e5 + 10;
 7 LL n, T, a[maxn];
 8 bool Find(LL x)
 9 {
10     LL t = 0, k = 0;
11     for (int i = 1; i <= n; i++) {
12         if (a[i] <= x)t -= (x - a[i]);
13         else t += (a[i] - x) / 2;
14     }
15     if (t>=0)return true;
16     return false;
17 }
18 int main()
19 {
20     ios::sync_with_stdio(false);
21     cin >> T;
22     while (T--) {
23         cin >> n;
24         LL l = 0, r = 0;
25         for (int i = 1; i <= n; i++) {
26             cin >> a[i]; r = max(r, a[i]);
27         }
28         while (l <= r) {
29             LL mid = (l + r) >> 1;
30             if (Find(mid))l = mid + 1;
31             else r = mid - 1;
32         }
33         cout << r << endl;
34     }
35     return 0;
36 }

 

 

F.rect

Problem Description

度度熊有一个大小为 MX imes MYMX×MY 的矩形,左下角坐标为 (0, 0)(0,0),右上角坐标为 (MX, MY)(MX,MY)。此矩形内有 NN 个整数坐标的点 (x_i, y_i)(x?i??,y?i??),x_ix?i?? 彼此不重复,y_iy?i?? 彼此也不重复。

现在要从每一个点画出一条线段,满足下列条件:

  • 线段起点为坐标点,终点在矩形范围的四个边界之一上。
  • 线段彼此不能交叉。

现在要让画出的线段的长度总和最小,请输出这个最小的长度总和值。

Input

输入的第一行有一个正整数 TT,代表接下来有几笔测试资料。

对于每笔测试资料: 第一行有三个整数 MXMX, MYMY 以及 NN。 接下来的 NN 行每行有两个正整数 x_ix?i?? 及 y_iy?i??。

  • 2 le MX, MY le 10^62MX,MY10?6??
  • 0 le N le 10^50N10?5??
  • 如果 i e jij,则保证 x_i e x_jx?i??x?j?? 及 y_i e y_jy?i??y?j??
  • 0 < x_i < MX0<x?i??<MX
  • 0 < y_i < MY0<y?i??<MY
  • 1 le T le 201T20
  • 至多 22 笔测试资料中的 N > 1000N>1000
Output

对于每一笔测试资料,请依序各自在一行内输出一个整数,代表可能的最小长度和。

Sample Input
2
4 4 1
2 2
10 7 3
6 3
2 6
9 5
Sample Output
2
5
思路:由于题目上说对于每个点(xi,yi),xi,yi都不重复出现,也就代表着如果对于每个点直接找它离边界最近的直线距离即可满足不相交的条件。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 
 5 using namespace std;
 6 long long T, n, x, y;
 7 int main()
 8 {
 9     ios::sync_with_stdio(false);
10     cin >> T;
11     while (T--) {
12         cin >> x >> y >> n;
13         long long ans = 0, a, b;
14         for (int i = 0; i<n; i++) {
15             cin >> a >> b;
16             ans += min(min(abs(a - 0), abs(x - a)), min(abs(b - 0), abs(y - b)));
17         }
18         cout << ans << endl;
19     }
20     return 0;
21 }

 

以上是关于2018百度之星初赛B - A,D,F的主要内容,如果未能解决你的问题,请参考以下文章

2018 “百度之星”程序设计大赛 - 初赛(B)

2017"百度之星"程序设计大赛 - 初赛(B)度度熊的交易计划

2016"百度之星" - 初赛(Astar Round2A) 1004 D Game 区间DP

2016 百度之星 初赛B - 瞬间移动(逆元)

2018 “百度之星”程序设计大赛 - 初赛(A)

百度之星2016初赛之部分题解