【BZOJ-3721】Final Bazarek 贪心

3721: PA2014 Final Bazarek

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 610  Solved: 243
[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

鸣谢Jcvb

Solution

贪心直接搞就可以

首先我们从大到小排序,然后处理出$sumV[i]$,$maxo[i]$,$maxe[i]$,$mino[i]$,$mine[i]$

分别表示:前缀和、后缀最大奇数、后缀最大偶数、前缀最小奇数、前缀最小偶数

然后对于一次询问K,如果$sumV[K]$为奇数,那么答案显然是$sumV[K]$

如果为偶数,考虑替换,把前缀最小奇数替换成后缀最大偶数,或前缀最小偶数替换成后缀最大奇数,这样取较大即可

这样替换,显然满足sum从偶变奇,且总和最大。

特判一下不合法的情况输出-1即可。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
#define MAXN 1000100
int N,K,M;
int val[MAXN],mine[MAXN],maxo[MAXN],mino[MAXN],maxe[MAXN];
LL sumV[MAXN];
#define INF 0x7fffffff
bool cmp(int x,int y) {return x>y;}
void PreWork()
{
    sort(val+1,val+N+1,cmp);
    for (int i=1; i<=N; i++) sumV[i]=sumV[i-1]+(LL)val[i];
    mine[0]=INF; mino[0]=INF;
    for (int i=1; i<=N; i++)
        mine[i]=min(mine[i-1],val[i]&1? INF:val[i]),
        mino[i]=min(mino[i-1],val[i]&1? val[i]:INF);
    maxo[N+1]=-INF; maxe[N+1]=-INF;
    for (int i=N; i>=1; i--)
        maxe[i]=max(maxe[i+1],val[i]&1? -INF:val[i]),
        maxo[i]=max(maxo[i+1],val[i]&1? val[i]:-INF);
}
inline LL Ask(int K)
{
    if (sumV[K]&1) return sumV[K];
    bool f1=0,f2=0; LL re=-INF;
    if (mino[K]!=INF && maxe[K+1]!=-INF) f1=1;
    if (mine[K]!=INF && maxo[K+1]!=-INF) f2=1;
    if (!f1 && !f2) return (LL)-1;
    if (f1) re=max(re,sumV[K]-mino[K]+maxe[K+1]);
    if (f2) re=max(re,sumV[K]-mine[K]+maxo[K+1]);
    return re;
}
int main()
{
    N=read();
    for (int i=1; i<=N; i++) val[i]=read();
    M=read();
    PreWork();
    while (M--) K=read(),printf("%lld\n",Ask(K));
    return 0;
}
时间: 2024-10-31 11:11:53

【BZOJ-3721】Final Bazarek 贪心的相关文章

【BZOJ3721】PA2014 Final Bazarek 贪心

[BZOJ3721]PA2014 Final Bazarek Description 有n件商品,选出其中的k个,要求它们的总价为奇数,求最大可能的总价. Input 第一行一个整数n(1<=n<=1000000),表示商品数量.接下来一行有n个整数,表示每件商品的价格,范围在[1,10^9].接下来一行有一个整数m(1<=m<=1000000),表示询问数量.接下来m行,每行一个整数k[i](1<=k[i]<=n). Output 对于每个询问,输出一行表示保证奇数的

BZOJ 3721 PA 2014 Final Bazarek 贪心

题目大意:有n件商品,选出其中的k个,要求它们的总价为奇数,求最大可能的总价. 思路:一个O(n)的贪心,先排序,然后O(n)预处理每个节点之前出现的最大奇数和偶数,和每一个节点之后出现的最小的奇数或者偶数,之后每个询问O(1)判断一下.注意初值. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 #d

BZOJ 3727 PA2014 Final Zadanie 贪心

题目大意:给定n个数,多次询问选择k个数使和为奇数的最大和 首先将所有数排序 对于每个询问,如果最大的k个数之和是奇数,那么答案显然是这k个数的和 如果最大的k个数之和是偶数,那么我可以将后k个数中最小的偶数换成前n-k个数中最大的奇数,或者将后k个数中最小的奇数换成前n-k个数中最大的偶数 二者取最优即可 无法如此做则输出-1 #include <cstdio> #include <cstring> #include <iostream> #include <a

【贪心】bzoj3721 PA2014 Final Bazarek

考虑不限制奇偶的情况,那就是直接排序取前k个的和. 加上奇偶限制:若排序后的前k个的和是偶数,则“显然地”:将其中的最小的奇数替换成未被选择的数中最大的偶数 或者 将其中的最小的偶数替换成未被选择的数中最大的奇数 是最优的. 那么排序之后 就可以预处理出 某个位置左侧最小的奇数.左侧最小的偶数.右侧最大的奇数.右侧最大的偶数,然后就可以O(1)地回答每个询问了. 开long long 1 #include<cstdio> 2 #include<algorithm> 3 using

CSU1603: Scheduling the final examination(贪心)

Description For the most of the university students,what they most want is that they can obtain 60 points from the final examination of every subject. Now, final examination is coming. As an excellent programmer,you are asked for help. The full mark

BZOJ 2430 Poi2003 Chocolate 贪心

题目大意:给定一个巧克力,怎么切看题目吧我实在写不动了= = 首先每条线被切至少一次 在此基础上一条线每被切一次就多付出一份代价 故每个交叉点上用权值较大的线切权值较小的线比较优 说白了就是大的先切然后小的后切 贪心的证明我说不明白了大家意会吧QAQ 一天之内写了整整十道题也是够受的了QAQ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #defin

[bzoj 2460]线性基+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460 网上很多题目都没说这个题目的证明,只说了贪心策略,我比较愚钝,在大神眼里的显然的策略还是想证明一下才安心--所以这里记录一下证明过程. 贪心策略:按魔力值从大到小排序,从大往小往线性基里插,如果成功插入新元素,就选这个,如果插不进去,就不选这个. 证明: 设有n个材料,每个材料的属性值是x[1],x[2],...,x[n],魔力值是v[1],v[2],...,v[n],这里假设v已

BZOJ 2460: [BeiJing2011]元素 贪心,线性基

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460 解法:从大到小排序,依次贪心的添加到当前集合就可以了,需要动态维护线性基.用拟阵证明,线性基性质,线性基中任意子集异或和不为0,所以从大到小加入就好. #include <bits/stdc++.h> using namespace std; typedef long long LL; struct node{ LL a, b; node(){} bool operator<

BZOJ 1293: [SCOI2009]生日礼物 贪心

1293: [SCOI2009]生日礼物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2513  Solved: 1370[Submit][Status][Discuss] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小