• E


    题目链接:https://codeforces.com/problemset/problem/658/E

    Codeforces is a wonderful platform and one its feature shows how much someone contributes to the community. Every registered user has contribution — an integer number, not necessarily positive. There are n registered users and the i-th of them has contribution ti.

    Limak is a little polar bear and he's new into competitive programming. He doesn't even have an account in Codeforces but he is able to upvote existing blogs and comments. We assume that every registered user has infinitely many blogs and comments.

    • Limak can spend b minutes to read one blog and upvote it. Author's contribution will be increased by 5.
    • Limak can spend c minutes to read one comment and upvote it. Author's contribution will be increased by 1.

    Note that it's possible that Limak reads blogs faster than comments.

    Limak likes ties. He thinks it would be awesome to see a tie between at least k registered users. To make it happen he is going to spend some time on reading and upvoting. After that, there should exist an integer value x that at least k registered users have contribution exactly x.

    How much time does Limak need to achieve his goal?

    Input

    The first line contains four integers nkb and c (2 ≤ k ≤ n ≤ 200 000, 1 ≤ b, c ≤ 1000) — the number of registered users, the required minimum number of users with the same contribution, time needed to read and upvote a blog, and time needed to read and upvote a comment, respectively.

    The second line contains n integers t1, t2, ..., tn (|ti| ≤ 109) where ti denotes contribution of the i-th registered user.

    Output

    Print the minimum number of minutes Limak will spend to get a tie between at least k registered users.

    Examples

    Input
    4 3 100 30
    12 2 6 1
    Output
    220
    Input
    4 3 30 100
    12 2 6 1
    Output
    190
    Input
    6 2 987 789
    -8 42 -4 -65 -8 -8
    Output
    0

    Note

    In the first sample, there are 4 registered users and Limak wants a tie between at least 3 of them. Limak should behave as follows.

    • He spends 100 minutes to read one blog of the 4-th user and increase his contribution from 1 to 6.
    • Then he spends 4·30 = 120 minutes to read four comments of the 2-nd user and increase his contribution from 2 to 6 (four times it was increaded by 1).

    In the given scenario, Limak spends 100 + 4·30 = 220 minutes and after that each of users 2, 3, 4 has contribution 6.

    In the second sample, Limak needs 30 minutes to read a blog and 100 minutes to read a comment. This time he can get 3 users with contribution equal to 12 by spending 100 + 3·30 = 190 minutes:

    • Spend 2·30 = 60 minutes to read two blogs of the 1-st user to increase his contribution from 2 to 12.
    • Spend 30 + 100 minutes to read one blog and one comment of the 3-rd user. His contribution will change from 6 to 6 + 5 + 1 = 12.

    题目大意:有n(2e5)个注册用户,每个人的贡献为t[i](±1e9范围)
    我们可以花费b的时间成本,使得一个人的贡献+5
    同样可以划分c的时间成本,使得一个人的贡献+1
    问你至少需要花费的时间,使得至少k(2<=k<=n)个注册用户拥有同样的贡献值。
    b,c∈[1,1000]
    (可能存在b<c)

    思路:

    这道题的总体思路是枚举答案,请记住这句话!!!

    仔细想想 ,答案会是哪些数呢? 我们要得到至少有K个数的值刚好等于x,我们总不可能从-1e9枚举到1e9吧,然后选取一个最小的时间花费

    想想x的值是不是一定是n个数中某个数+0 +1 +2 +3 +4的后的值。  仔细想想,发现一定是的,如果+5的话,那还不如是本身呢 ,这一点自己仔细想想,只可意会,不可言传

    再多说一句,为什么要+1 +2 +3 +4  因为题目说会出现+5所需的花费比+1所需的花费更小的情况

    到此时 我们的复杂度是 5*N  因为我们每个数都得枚举

    那么我们怎么快速求出对应每个ans下的总花费呢?  如果对于每个ans再跑一遍for 很显然是不行的

    这里使用一种贪心的思想,保证在log的复杂度内求出答案

    我们按照每个数的初始贡献度从小往大排序,那么如果当前选中的数还不到K个的时候直接加进去就好了,当满了K个的时候,我们去掉一个怎样的数才是最优的呢?

    直接说吧,去掉一个到达目标贡献度所需花费最大的那个。

    新学了一种目标线的思想,自己也不是很懂:下面是学习博客上说的:
    我们假设所有数所要达成的目标是aim,并使得aim为5的倍数
    (尽管aim可能不是5的倍数,但我们可以使得所有数都向上平移1、2、3、4,也就相当于处理了aim%5==0、1、2、3、4的所有情形)

    然后,我们不妨从最小的数开始枚举,这些数所要达成的目标是5的倍数。
    所以,如果其不是5的倍数,那么我们要加进一些c1类成本,使其变为5的倍数。
    然后,这个数后来要达成的数aim是5的几倍,我们并不知道。
    然而,我们利用目标线思想,先把这个数距离0的差值减去,
    然后,当我们这个数要达到的目标为val时,我们再把需要增加的值加回来即可。

    这种目标线思想非常奇妙而实用。
    当我们目前所选数字的个数>=k个的时候,我们就可以更新答案了。
    用当前的成本,加上达到平行线的剩余成本,来更新答案。

    同时基于贪心,肯定此时扔掉费用最大的一个。

    看代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<list>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ull;
    const int maxn=2e5+5;
    const int maxm=100000+10;
    const ull base=2333;
    const LL INF=1e18;
    LL N,K,B,C;
    LL a[maxn];
    int main()
    {
        scanf("%lld%lld%lld%lld",&N,&K,&B,&C);
        B=min(B,5*C);//保证+5个贡献值 使用最少的时间
        for(int i=1;i<=N;i++)
        {
            scanf("%lld",&a[i]);
    //        a[i]+=1e9;//
        }
        sort(a+1,a+1+N);
        LL ans=INF;
        ///此解法相当于枚举答案
        for(int i=0;i<5;i++) //答案只会在某个数 +1 ~ 4 之间
        {
            priority_queue<LL>q;
            LL sum=0;
            for(int j=1;j<=N;j++)
            {
                a[j]++;//
                LL val=(a[j]+4)/5*5;//向上取整达到5的倍数后的值
                LL cnt=(val-a[j])*C-val/5*B;//到达本身的贡献值所需要的时间花费 不过这里存的是它的相反数 方便优先队列处理
                q.push(cnt);
                sum+=cnt;
    //            cout<<"sum:"<<sum<<"val:"<<val<<endl;
                if(q.size()==K)//到了K个数
                {
                    ans=min(ans,sum+K*val/5*B);
                    sum-=q.top();//弹出一个所需时间最少的 (也就是负数最大)
                    q.pop();
    //                cout<<"ans:"<<ans<<endl;
                }
    
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    /**
    2 2 1 2
    6 10
    */
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    栈和堆的详细介绍
    在DataTable中执行DataTable.Select("条件")返回DataTable;
    委托和事件
    面试宝典
    sql的寫法,推薦的寫法,全文索引提高類似like查詢的效率
    Google地图
    一般处理程序中,获取session
    提交表单
    手脱tElock 0.98b1 -> tE!
    手脱FSG 2.0 -> bart/xt
  • 原文地址:https://www.cnblogs.com/caijiaming/p/11945251.html
Copyright © 2020-2023  润新知