BZOJ 3721: PA2014 Final Bazarek

 

3721: PA2014 Final Bazarek

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 645  Solved: 261
[Submit][Status][Discuss]

Description

有n件商品,选出其中的k个,要求它们的总价为奇数,求最大可能的总价。

Input

第一行一个整数n(1<=n<=1000000),表示商品数量。
接下来一行有n个整数,表示每件商品的价格,范围在[1,10^9]。
接下来一行有一个整数m(1<=m<=1000000),表示询问数量。
接下来m行,每行一个整数k[i](1<=k[i]<=n)。

Output

对于每个询问,输出一行表示保证奇数的情况下最大的总价。若无法满足要求,输出-1。

Sample Input

4
4 2 1 3
3
2
3
4

Sample Output

7
9
-1

HINT

 

Source

[ Submit][ Status][ Discuss]

 

先对所有数字按照从大到小的顺序排序,然后维护前缀和,以及最小前缀(奇数/偶数),最大后缀(奇数/偶数)。

当询问K个的时候,如果sum[k]凑巧是个奇数,那么答案就是sum[k],否则就考虑用一个未添加的奇数换一个已添加的偶数,或是用一个未添加的偶数换一个已添加的奇数,二者取其大。

 

 1 #include <bits/stdc++.h>
 2 
 3 template <class T>
 4 inline void read(T &x) {
 5     char c = getchar(); x = 0;
 6     while (c < '0')
 7         c = getchar();
 8     while (c >= '0') {
 9         x = x*10 + c - '0';
10         c = getchar();
11     }
12 }
13 
14 template <class T>
15 inline T Max(const T &a, const T &b) {
16     return a > b ? a : b;
17 }
18 
19 template <class T>
20 inline T Min(const T &a, const T &b) {
21     return a < b ? a : b;
22 }
23 
24 inline int cmp(const void *a, const void *b) {
25     return - *(int *)a + *(int *)b;
26 }
27 
28 typedef long long longint;
29 
30 const int inf = 2e9 + 9;
31 
32 const int siz = 1000005;
33 
34 int n, m;
35 int num[siz];
36 int min[siz][2];
37 int max[siz][2];
38 longint sum[siz];
39 
40 inline void prework(void) {
41     qsort(num + 1, n, sizeof(int), cmp);
42     
43     memset(sum, 0, sizeof(sum));
44     
45     for (int i = 0; i < siz; ++i)
46         min[i][0] = min[i][1] = inf,
47         max[i][0] = max[i][1] = -inf;
48     
49     for (int i = 1; i <= n; ++i)
50         sum[i] = sum[i - 1] + num[i];
51     
52     for (int i = 1; i <= n; ++i) {
53         int a = num[i] & 1, b = a ^ 1;
54         min[i][a] = num[i];
55         min[i][b] = min[i - 1][b];
56     }
57     
58     for (int i = n; i >= 1; --i) {
59         int a = num[i] & 1, b = a ^ 1;
60         max[i][a] = num[i];
61         max[i][b] = max[i + 1][b];
62     }
63 }
64 
65 inline bool judge(int k) {
66     return 
67         (min[k][0] == inf || max[k + 1][1] == -inf)
68     &&  (min[k][1] == inf || max[k + 1][0] == -inf);
69 }
70 
71 inline void query(int k) {
72     if (sum[k] & 1)
73         printf("%lld\n", sum[k]);
74     else if (judge(k))puts("-1");
75     else printf("%lld\n", 
76         sum[k] + Max(
77             - min[k][0] + max[k + 1][1],
78             - min[k][1] + max[k + 1][0])
79         );
80 }
81 
82 signed main(void) {
83     read(n);
84     
85     for (int i = 1; i <= n; ++i)
86         read(num[i]);
87         
88     prework();
89         
90     read(m);
91     
92     for (int i = 1, k; i <= m; ++i)
93         read(k), query(k);
94 }

 

@Author: YouSiki

转载于:https://www.cnblogs.com/yousiki/p/6145057.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值