• 题解 DTOJ #2305.Bazarek


    欢迎访问 My Luogu Space


    【题目描述】

    小Bajtek和他的奶奶在度假。每天早晨,奶奶会去一个集市(bazarek)上买东西。男孩很快发现一个规律:他的奶奶每天的购物金额都是奇数。毕竟人老了就会有些死板嘛,每个祖母或多或少都这样。 男孩会提供含有n个商品的清单,奶奶从里面挑选若干个购买。每一天,奶奶会告诉男孩她要买k个商品,然后让男孩带够钱跟她去。但是他并不知道奶奶会买哪k个商品(但它们总价一定是奇数),所以他想知道这一天至少要带多少钱。

    【输入输出格式】

    输入格式:

    第一行一个整数n(1<=n<=1000000),表示商品数量。

    接下来一行有n个整数,表示每件商品的价格,范围在[1,10^9]。

    接下来一行有一个整数m(1<=m<=1000000),表示询问数。

    接下来m行,每行一个整数ki。

    输出格式:

    对于每个询问,输出一行表示至少要带多少钱。若无法满足要求,输出-1。

    【输入输出样例】

    输入样例:

    4
    4 2 1 3
    3
    2
    3
    4

    输出样例:

    7
    9
    -1


    【标签】

    模拟,预处理,读优。


    【分析】

    考虑 预处理+在线 的做法。

    基本想法:

    先将所有物品按从大到小排序,对于每个访问,先从大到小将 (k) 个物品拿上。

    如果此时的价格之和为奇数,那么直接输出;

    如果为偶数,那么

    1. 将已选的物品中最小的偶数价格删去,加入没选的物品中最大的奇数价格,

    2. 将已选的物品中最小的奇数价格删去,加入没选的物品中最大的偶数价格,

    取以上两种做法中价格较大的作为答案输出。

    改进:

    考虑到数据范围过大,采用预处理的方式,将数据读入,把数据范围内可能的所有答案预处理出来,再读入每个 (m) 对当前的 (m) 进行在线输出。

    1. 预处理出在取到种数量的物品时的未选的最大奇数和偶数价格,以及已选的最小奇数和偶数价格,方便后续调用。

    2. 从少到多将所有k的答案预处理出来,记录到答案数组当中。读入 (k),直接输出 (Ans[k])


    【代码 】

    [C++]

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MAXN = 1000000+5;
    
    int n, m, S[MAXN], MaxOd[MAXN], MaxEv[MAXN];  //odd n.奇数 ,even n.偶数 
    LL Ans[MAXN], sum; 
    
    inline int rd(){  //读入优化 
        char s;
        while(!isdigit(s=getchar()));
        int x=(s^48);
        while(isdigit(s=getchar())) x = (x<<1)+(x<<3)+(s^48);
        return x;
    }
    int main(){
    	n=rd();
    	for(int i=1; i<=n; i++) S[i]=rd();
    	sort(S+1, S+n+1, greater<int>());  //从大到小排序 
    	int odd = 0, eve = 0;
    	for(int i=n; i>=1; i--){  //处理所有情况下的未选最大奇数偶数价格,因为数组有序,直接更新,下同 
    		MaxOd[i] = odd;
    		MaxEv[i] = eve;
    		if(S[i]&1) odd = S[i];
    		else eve = S[i];
    	}
    	odd = eve = 0;
    	for(int i=1; i<=n; i++){  //处理出所有答案 
    		if(S[i]&1) odd = S[i];  //处理出已选最小奇数偶数价格 
    		else eve = S[i];
    		sum += S[i];
    		if(sum&1) Ans[i] = sum;
    		else{
    			if(MaxOd[i] && eve) Ans[i] = max(Ans[i], sum-eve+MaxOd[i]);  //如果能取才取,取二者最大值 
    			if(MaxEv[i] && odd) Ans[i] = max(Ans[i], sum-odd+MaxEv[i]);
    			if(!Ans[i]) Ans[i] = -1;
    		}
    	}
    	int k;
    	for(m=rd(); m--;) k = rd(), printf("%lld
    ", Ans[k]);
    	return 0;
    }
    

    【补充】

    快写很慢!!很慢!

    Over

  • 相关阅读:
    app已损坏,打不开。你应该将它移到废纸篓。
    Mac/win eclipse genymotion 插件下载地址
    过大年
    error: L6235E: More than one section matches selector
    android socket 线程连接openwrt与arduino单片机串口双向通信
    PCB对应封装元件名称
    网页代码总结
    sql一个表中的数据插入到另外一个表中
    树莓派更换镜像源
    SQL 中的 AND OR
  • 原文地址:https://www.cnblogs.com/bosswnx/p/10570804.html
Copyright © 2020-2023  润新知