题目链接: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 }