【VK Cup 2016 - Round 1 (Div 2 Edition)E】【目标线思想差值相减 优先队列】Bear and Contribution c5成本+5 c1成本+1使得至少k人贡献相

Bear and Contribution
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 2e5+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int n, k;
int a[N];
LL c5, c1;
int main()
{
	while (~scanf("%d%d%lld%lld", &n, &k, &c5, &c1))
	{
		gmin(c5, c1 * 5);
		for (int i = 1; i <= n; ++i)scanf("%d", &a[i]), a[i] += 1e9;
		sort(a + 1, a + n + 1);
		LL ans = 4e17;//2e5*2e9*1e3;
		for (int mod = 0; mod < 5; ++mod)
		{
			priority_queue<LL>q;
			LL sum = 0;
			for (int i = 1; i <= n; ++i)
			{
				int aim = (a[i] + 4) / 5 * 5;
				LL cost = (aim - a[i])*c1 - aim / 5 * c5;
				sum += cost;
				q.push(cost);
				if (q.size() == k)
				{
					gmin(ans, sum + aim / 5 * c5 * k);
					sum -= q.top();
					q.pop();
				}
			}
			for (int i = 1; i <= n; ++i)++a[i];
		}
		printf("%lld\n", ans);
	}
	return 0;
}
/*
【trick&&吐槽】
目标平行线思想 差值相减非常巧妙 棒棒棒

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

【类型】
贪心 双指针计数

【分析】
想法一:
首先,有一点可以明确的是,答案肯定在
{某个人的贡献+0,+1,+2,+3,+4}的集合中。
于是有一种做法,就是我们枚举答案,然后统计权值。

想法二:
题目中有提到可能存在b<c,这种不单调性会对我们的解题策略有所影响。
一般而言,比较有利的单调性是——
b>c&&b<5*c
即:	1,如果b>5*c,那么b就没有任何选择的意义,显然我们可以用5*c替代b
	2,做完操作1之后,c的性价比就严格不比b优,那么我们选择c的条件就是需要实现末端对齐。


结合想法一,在执行想法二的操作1和操作2之后,我们枚举答案。
假设,我们需要使得至少k个数达到aim,那么我们会怎么选择呢?

显然,这里有个单调性,
1,我们当前尝试达到aim的数x要严格<=aim
2,对于mod 5 == p 的数,我们所选取的话,必然会选取尽可能大的。

于是这里有了一种策略。
就是我们枚举所要达到的目标时,
把所有%5同余的数放在一起处理。
最先操作的时候,把所有能达成其的数按照成本高低排序。并取成本最小的k个

然后当这个数-5的时候,有些数字不符合,如果不符合的数字在我们选取的区间内,
那我们就要贪心继续多取一些数。
这种做法的复杂度是O(5nlogn)

======================然而最优美的代码还是利用优先队列====================

要理解这种思路,还要搭配上目标线思想。
我们假设所有数所要达成的目标是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个的时候,我们就可以更新答案了。
用当前的成本,加上达到平行线的剩余成本,来更新答案。

同时基于贪心,肯定此时扔掉费用最大的一个。
重复这个过程,便可以AC这道题。

【时间复杂度&&优化】
O(5nlogn)

*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值