[CF798D] Mike and distribution(贪心,鸽笼原理,随机)

题目链接:http://codeforces.com/contest/798/problem/D

题意:两个数列a、b,分别有n个数。希望选出下标相同的尽可能少的数字,使得它们分别的和为两个数列中数字分别总和的一半,尽可能少指的是≤  。只要在这个范围内,都算符合条件。

不妨就认为题目是要选个数字,使得满足条件。题目要求二倍的选中的数字-原数字总和>0,同时减掉一倍选中的数字和,问题转换成了选个数,使得选中的数的总和比剩下的数的综合大。

由于选了,可以先给a排序,记下a的id和val。a中的数必然选择最大的那个,这样能保证接下来选择能同时满足:a中选的数比另一个数大;从a(i).id和a(i+1).id选b较大的一个,这样能保证b中的数字一个大的比一个小的大,选其中大的那个数,总和当然比剩下的大。稍微想一下觉得这个和鸽巢原理有关系。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 typedef struct X {
 6     int id, val;
 7 }X;
 8 const int maxn = 100100;
 9 int n, m;
10 X a[maxn], b[maxn];
11 
12 int main() {
13     // freopen("in", "r", stdin);
14     while(~scanf("%d", &n)) {
15         for(int i = 1; i <= n; i++) {
16             scanf("%d", &a[i].val);
17             a[i].id = i;
18         }
19         for(int i = 1; i <= n; i++) {
20             scanf("%d", &b[i].val);
21             b[i].id = i;
22         }
23         m = n / 2 + 1;
24         sort(a+1, a+n+1, [](X a,X b){return a.val>b.val;});
25         int pa = n, pb = n;
26         vector<int> ret;
27         ret.push_back(a[1].id);
28         for(int i = 2; i <= n; i+=2) {
29             if(i + 1 <= n && b[a[i].id].val < b[a[i+1].id].val) ret.push_back(a[i+1].id);
30             else ret.push_back(a[i].id);
31         }
32         printf("%d
", m);
33         for(int i = 0; i < ret.size(); i++) {
34             printf("%d%c", ret[i], i==ret.size()-1?'
':' ');
35         }
36     }
37     return 0;
38 }

看讨论版还有用random随出来的,感觉O(能过)。。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const int maxn = 100100;
 6 int n, m, a[maxn], b[maxn], p[maxn];
 7 LL sa, sb;
 8 
 9 bool ok() {
10     LL ta = 0, tb = 0;
11     for (int i = 1; i <= m; ++i) {
12         ta += 2LL * a[p[i]], tb += 2LL * b[p[i]];
13         if (ta > sa && tb > sb) return 1;
14     }
15     return 0;
16 }
17 
18 int main() {
19     // freopen("in", "r", stdin);
20     while(~scanf("%d", &n)) {
21         sa = sb = 0;
22         for (int i = 1; i <= n; i++) {
23             scanf("%d", &a[i]);
24             sa += a[i]; p[i] = i;
25         }
26         for (int i = 1; i <= n; i++) {
27             scanf("%d", &b[i]);
28             sb += b[i];
29         }
30         m = n / 2 + 1;
31         while (!ok()) random_shuffle(p + 1, p + 1 + n);
32         printf("%d
", m);
33         for (int i = 1; i <= m; i++) printf("%d%c", p[i], i==m?'
':' ');
34     }
35     return 0;
36 }
原文地址:https://www.cnblogs.com/kirai/p/6873243.html