C. Ticket Hoarding

C. Ticket Hoarding

As the CEO of a startup company, you want to reward each of your k employees with a ticket to the upcoming concert. The tickets will be on sale for n days, and by some time travelling, you have predicted that the price per ticket at day i will be ai. However, to prevent ticket hoarding, the concert organizers have implemented the following measures:

  • A person may purchase no more than m tickets per day.
  • If a person purchases x tickets on day i, all subsequent days (i.e. from day i+1 onwards) will have their prices per ticket increased by x.

For example, if a=[1,3,8,4,5] and you purchase 2 tickets on day 1, they will cost 2 in total, and the prices from day 2 onwards will become [5,10,6,7]. If you then purchase 3 more tickets on day 2, they will cost in total an additional 15, and the prices from day 3 onwards will become [13,9,10].

Find the minimum spending to purchase k tickets.

Input

Each test contains multiple test cases. The first line contains an integer t (1t104) — the number of test cases. The description of the test cases follows.

The first line of each test case contains three integers n, m, and k (1n3105,1m109,1kmin(nm,109)) — the number of sale days, the maximum amount of ticket purchasable each day, and the number of tickets to be bought at the end.

The second line of each test case contains n integers a1,a2,,an (1ai109) — the price per ticket for each of the upcoming n days.

It is guaranteed that the sum of n over all test cases does not exceed 3105.

Output

For each test case, print one integer: the minimum amount of money needed to purchase exactly k tickets.

Example

input

4
4 2 3
8 6 4 2
4 2 8
8 6 4 2
5 100 1
10000 1 100 10 1000
6 3 9
5 5 5 5 5 5

output

10
64
1
72

Note

In the first test case, one optimal way to buy 3 tickets is as follows:

  • Buy 0 tickets on the first day. The prices per ticket for the remaining days are [6,4,2].
  • Buy 0 tickets on the second day. The prices per ticket for the remaining days are [4,2].
  • Buy 1 ticket on the third day with cost 4. The price per ticket for the remaining day is [3].
  • Buy 2 tickets on the fourth day with cost 6.

In the second test case, there is only one way to buy 8 tickets:

  • Buy 2 tickets on the first day with cost 16. The prices per ticket for the remaining days are [8,6,4].
  • Buy 2 tickets on the second day with cost 16. The prices per ticket for the remaining days are [8,6].
  • Buy 2 tickets on the third day with cost 16. The price per ticket for the remaining day is [8].
  • Buy 2 tickets on the fourth day with cost 16.

 

解题思路

  直观的贪心思路是,选择最小的 x=kmai 购买,其中前 x1ai 购买的数量均为 m,第 xai 购买的数量为 k(x1)m。下面给出证明。

  用 bi(0bim) 表示购买 ai 的数量,且 i=1nbi=k。购买 ai 的代价就是 (ai+j=1i1bj)bi。因此总代价就是:

i=1n(ai+j=1i1bj)bi=i=1naibi+i=1nbij=1i1bj

  可以证明,将 (ai,aj)(aj,bj) 进行交换,上述等式的值不变。其中 i=1naibi 这部分显然没有变化,下面证明 i=1nbij=1i1bj 这部分也是不变的。

  不失一般性,假设 ij,将 i=1nbij=1i1bj 根据 ij 分成三部分的和 k=1i1bku=1k1bu+k=ijbku=1k1bu+k=j+1nbku=1k1bu。其中 k=1i1bku=1k1bu 这部分显然没有变化,因为没有涉及到 bibjk=j+1nbku=1k1bu 这部分也没有变化,因为 bibj 只会出现在 u=1k1bu 中,而顺序并不会影响求和的结果。

  剩下的就是 k=ijbku=1k1bu,在 (ai,aj)(aj,bj) 交换后,考虑 biu=1i1buk=i+1j1bku=1k1bubju=1i1bu 这三部分发生的变化:

bju=1i1bubiu=1i1bu+biu=1j1bubi2+bibjbju=1j1bu+bjk=i+1j1bkbik=i+1j1bk=(bibj)u=1j1bu(bibj)u=1i1bu(bibj)u=i+1j1bubi(bibj)=(bibj)u=ij1bu(bibj)u=i+1j1bubi(bibj)=(bibj)bibi(bibj)=0

  这意味着我们当我们确定购买的方案 bi 后,以任意顺序购买 ai,得到的代价都不变。对 ai 进行升序排序,并构造方案 b=[m,m,,mx1,k(x1)m,0,0,,0]。可以证明该购买方案得到的代价最小。

  其中 i=1naibi 这部分根据排序不等式显然在 0bimi=1nbi=k 的限制下,得到的结果最小。而另外一部分由于 (i=1nbi)2=i=1nbi2+2i=1nbij=1i1bj,从而推出 i=1nbij=1i1bj=12k212i=1nbi2。从而只需证明 i=1nbi2 得到的结果最大。如果存在两个 ij 满足 0<bibj<m,那么用 (bi1,bj+1) 取代 (bi,bj),则 (bi1)2+(bj+1)2=bi2+bj2+2(bjbi+1)>bi2+bj2 即结果会变大。容易知道当 bi 为上述方案时,i=1nbi2 的结果最大,从而 12k212i=1nbi2 的结果最小。

  证毕。

  AC 代码如下,时间复杂度为 O(nlogn)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 3e5 + 5;

int a[N];

void solve() {
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 0; i < n; i++) {
        scanf("%d", a + i);
    }
    sort(a, a + n);
    LL ret = 0;
    for (int i = 0, s = 0; i < n; i++) {
        int t = min(k, m);
        ret += (LL)t * (a[i] + s);
        k -= t;
        s += t;
    }
    printf("%lld\n", ret);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Global Round 25 Editorial:https://codeforces.com/blog/entry/128116

posted @   onlyblues  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示