• BZOJ 3721: PA2014 Final Bazarek【乱搞】


    有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

    思路:如果不要是奇数,那么..........排个序 输出前K个。。。。。。。。。。。。。

    如果前K个已经是奇数的话直接输出即可

    如果不是呢?

    思考熊。。。

    果断猜了个命题:设第K大的数为X,将X替换成不在前K大的和X奇偶性不一样的最大的数,这样一定是最优的。

    仔细思考了后发现这个命题不够完善 例如下面这个数据:

    5

    2 99 101 102 133

    1000

    2

    3

    唔 K=3时用上面那个算法做出来的是133+102+2 但最优的是133+101+99

    于是完善了上面的算法:设在前K大的数中与X奇偶性相同的最小的数为Y(如果存在的话),那么把Y当成X替换成不在前K大中的奇偶性与Y不同的最大的那个数 这样算出的数和上面算法一算出的数取个最大值就是答案了

    然后YY了个证明:设Bi表示i个数不在前k大数中的K个数的和的最大值,则Bi>=B(i+1),即i+1个数不在前K大里的答案绝对不优于i个数不在前K大里的答案

    因此优先考虑0个数不在前K大里 即就是前K大的和 如果不为奇数,那么考虑只有1个数不在前K大里,显然通过以上方法一定能将和调整为奇数,或者题目无解。

    接下来考虑为何用以上算法是调整一个数时的最大值:显然由于此时前K大的和为偶数,因此调整一个数要么把奇数调整成一个偶数,要么把偶数调整成一个奇数,那显然就是将最小的偶数调整成最大的奇数 或者最小的奇数调整成最大的偶数就可以了

    //bzoj2464

    #include <stdio.h>

    #include <string.h>

    #include <algorithm>

    #include <iostream>

    #define maxn 1000009

    using namespace std;

    int a[maxn],foredif[maxn],same[maxn],badif[maxn];

    long long sum[maxn];

    int cmp(int x, int y){return x>y;}

    long long mmax(long long x,long long y)

    {

        return x>y?x:y;

    }

    int main()

    {

        long long n,k,lasto=-1,laste=-1,m;

        scanf("%lld",&n);

        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);

        sort(a+1,a+1+n,cmp);

        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];

        for(int i=1;i<=n;i++)

        {

            if((a[i]&1)==1)//odd

            {

                foredif[i]=laste;

                lasto=i;

            }

            else

            {

                foredif[i]=lasto;

                laste=i;

            }

        }

        lasto=laste=-1;

        for(int i=n;i>=1;i--)

        {

            if((a[i]&1)==1)//odd

            {

                same[i]=lasto;

                badif[i]=laste;

                lasto=i;

            }

            else

            {

                same[i]=laste;

                badif[i]=lasto;

                laste=i;

            }

        }

        scanf("%lld",&m);

        for(int i=1;i<=m;i++)

        {

            scanf("%lld",&k);

            long long s=sum[k];

            if((s&1)==1){printf("%lld ",s);continue;}

            if(badif[k]==-1)

            {

                if(same[k]==-1||foredif[k]==-1)s=-1;else

                    s=(long long)s+(long long)a[same[k]]-(long long)a[foredif[k]];

            }

            else

            {

                if(same[k]==-1||foredif[k]==-1)s=s-(long long)a[k]+(long long)a[badif[k]];

                else

                {

                    s=mmax((long long)s+(long long)a[same[k]]-(long long)a[foredif[k]],(long long)s-(long long)a[k]+(long long)a[badif[k]]);

                }

            }

            printf("%lld ",s);

        }

        return 0;

    }

  • 相关阅读:
    关于接口与抽象类
    C# 高级编程(笔记4)
    泛型与委托
    C# 高级编程(笔记2)
    构造函数的代码膨胀问题
    C# 高级编程(笔记3)
    C# 高级编程(笔记1)
    Web(7)补充
    理解synchronized对象锁
    robbin谈管理:改造团队的经验
  • 原文地址:https://www.cnblogs.com/philippica/p/4103903.html
Copyright © 2020-2023  润新知