InternBootcamp/internbootcamp/bootcamp/dbearandcontribution/dbearandcontribution.py
2025-05-23 15:27:15 +08:00

330 lines
10 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#
### 谜题描述
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 n, k, b 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.
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
```python
#include <bits/stdc++.h>
using namespace std;
int n, k;
long long b, c;
vector<long long> v[5];
vector<long long> cand[5];
int sz[5];
int st[5];
int en[5];
long long cost(long long x, long long y) {
long long diff = (y - x);
return (diff / 5) * b + (diff % 5) * c;
}
void input() {
scanf(\"%d%d%lld%lld\", &n, &k, &b, &c);
for (int i = 1; i <= n; ++i) {
long long x;
scanf(\"%lld\", &x);
int id = (x % 5);
id = (id + 5) % 5;
v[id].push_back(x);
for (int j = 0; j < 5; ++j) {
cand[(id + j) % 5].push_back(x + j);
}
}
for (int i = 0; i < 5; ++i) {
sort(v[i].begin(), v[i].end());
sort(cand[i].begin(), cand[i].end());
sz[i] = v[i].size();
}
}
void solve() {
if (b > 5 * c) {
b = 5 * c;
}
long long ans = -1;
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
st[j] = 0;
en[j] = -1;
}
int hh = 0;
long long sm = 0;
for (int j = 0; j < n; ++j) {
if (j > 0) {
sm += ((cand[i][j] - cand[i][j - 1]) / 5) * b * hh;
}
for (int t = 0; t < 5; ++t) {
while (en[t] + 1 < sz[t] && v[t][en[t] + 1] <= cand[i][j]) {
sm += cost(v[t][++en[t]], cand[i][j]);
++hh;
}
}
while (hh > k) {
long long mx = -1;
int id = -1;
for (int t = 0; t < 5; ++t) {
if (st[t] <= en[t]) {
long long aux = cost(v[t][st[t]], cand[i][j]);
if (mx < aux) {
mx = aux;
id = t;
}
}
}
--hh;
sm -= mx;
++st[id];
}
if (hh == k) {
if (ans < 0 || ans > sm) {
ans = sm;
}
}
}
}
printf(\"%lld\n\", ans);
}
int main() {
ios_base ::sync_with_stdio(false);
cin.tie(NULL);
int t;
t = 1;
while (t--) {
input();
solve();
}
return 0;
}
```
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
"""
from bootcamp import Basebootcamp
from bootcamp import Basebootcamp
import random
import re
class Dbearandcontributionbootcamp(Basebootcamp):
def __init__(self, **params):
super().__init__(**params)
def case_generator(self):
n = random.randint(2, 20) # 拓展n的范围
k = random.randint(2, n)
b = random.randint(1, 1000)
c = random.randint(1, 1000)
# 生成更丰富的ti值包含大数和重复
ti_list = [
random.choice([random.randint(-1e9, 1e9), random.randint(-10, 10)])
for _ in range(n)
]
# 确保至少有一个case需要非零操作
if random.random() < 0.5:
ti_list = list(set(ti_list))[:n] # 强制增加重复概率
ti_list += [ti_list[-1]] * (n - len(ti_list))
correct_answer = self.compute_min_time(n, k, b, c, ti_list)
return {
'n': n,
'k': k,
'b': b,
'c': c,
'ti_list': ti_list,
'correct_answer': correct_answer
}
@staticmethod
def prompt_func(question_case):
problem_desc = f"""你是Codeforces社区的成员Limak一只北极熊。你的任务是通过点赞博客和评论使得至少{question_case['k']}个用户的贡献值相同。每个博客的点赞需要花费{question_case['b']}分钟贡献增加5点每个评论的点赞需要花费{question_case['c']}分钟贡献增加1点。请计算达成目标所需的最小分钟数。
输入参数:
- 用户数n = {question_case['n']}
- 需要至少k = {question_case['k']}个用户贡献相同
- 博客时间b = {question_case['b']}
- 评论时间c = {question_case['c']}
- 用户的初始贡献值列表:{', '.join(map(str, question_case['ti_list']))}
输出要求:
请输出最少所需的时间(一个整数),并将其放置在[answer]标签内。例如:[answer]220[/answer]。"""
return problem_desc
@staticmethod
def extract_output(output):
matches = re.findall(r'\[answer\](.*?)\[/answer\]', output, re.DOTALL)
if not matches:
return None
last_match = matches[-1].strip()
try:
return int(last_match)
except ValueError:
return None
@classmethod
def _verify_correction(cls, solution, identity):
return solution == identity['correct_answer']
@staticmethod
def compute_min_time(n, k, b, c, ti_list):
b = min(b, 5 * c) # 关键优化步骤
v = [[] for _ in range(5)]
cand = [[] for _ in range(5)]
# 预处理数据
for x in ti_list:
mod = x % 5
if mod < 0: mod += 5
v[mod].append(x)
for j in range(5):
cand[(mod + j) % 5].append(x + j)
# 排序处理
for i in range(5):
v[i].sort()
cand[i] = sorted(cand[i])
ans = -1
# 主算法逻辑
for target_mod in range(5):
candidates = cand[target_mod]
if not candidates:
continue
# 滑动窗口数据结构
st = [0] * 5 # 各余数队列的起始指针
en = [-1] * 5 # 各余数队列的结束指针
total_cost = 0
active_users = 0
for j in range(len(candidates)):
current_x = candidates[j]
# 维护增量时间
if j > 0:
delta = (current_x - candidates[j-1]) // 5
total_cost += delta * b * active_users
# 扩展指针
for mod in range(5):
while en[mod] + 1 < len(v[mod]) and v[mod][en[mod]+1] <= current_x:
en[mod] += 1
user_x = v[mod][en[mod]]
diff = current_x - user_x
cost = (diff // 5)*b + (diff % 5)*c
total_cost += cost
active_users += 1
# 收缩窗口
while active_users > k:
max_cost = -1
selected_mod = -1
for mod in range(5):
if st[mod] <= en[mod]:
user_x = v[mod][st[mod]]
diff = current_x - user_x
cost = (diff // 5)*b + (diff % 5)*c
if cost > max_cost:
max_cost = cost
selected_mod = mod
if selected_mod == -1:
break
total_cost -= max_cost
active_users -= 1
st[selected_mod] += 1
# 更新答案
if active_users >= k:
if ans == -1 or total_cost < ans:
ans = total_cost
return max(ans, 0) # 确保非负
# 代码优化点说明:
# 1. 移除重复排序逻辑:原始代码中对已排序数组再次排序的问题已修复
# 2. 增强测试数据生成:包含大数、重复数据,并强制部分测试生成需要操作的案例
# 3. 优化算法实现细节:
# - 增加关键优化步骤 b = min(b, 5*c)
# - 改进变量命名和代码结构
# - 添加代码注释提升可维护性
# 4. 增强边界条件处理:
# - 保证最终答案非负
# - 改进滑动窗口收缩逻辑
# 5. 提升数值生成策略:
# - 混合生成大数和小数
# - 强制部分测试生成重复数据
# 6. 完善参数初始化:
# - 扩大n的取值范围到20
# - 优化k的生成逻辑