codeforces 657C - Bear and Contribution [想法题]

题目链接: http://codeforces.com/problemset/problem/657/C

--------------------------------------------------------------------------------------------------------

题目的特别之处在于只有 $+1$ $+5$ 这两种操作 我们要考虑如何利用这个条件

多想一下后可以发现 如果最优解的目标值为$x($将至少$k$个人的值增加到$x)$

那么一定存在一个人 他的初始值在 $[x - 4, x]$ 这个范围内

否则将$x$减去$5$后可以得到更优的解

因此可能成为最优解的目标值最多只有 $n * 5$ 种

现在考虑的便是在 $O(n)$ 枚举目标值的前提下 如何对于每个目标值快速计算出答案

我一开始的想法是根据 $mod 5$ 的余数分类 写$5$个数组记录下前缀和什么的

然而这样二分答案有一个 $log$ 二分数组下标又一个 $log$

尽管题目给了 $4s$ 应该可以过 但是总感觉这样做不够优雅

再次分析题目条件我们有可以发现 实际上每次询问都是与目标距离最小的 $k$ 个数 而这个$k$是不变的

于是现在问题就变成了维护一个数据结构 支持查找容器内最小的 $k$个数 以及添加一个数

这显然就是一个堆了 总的复杂度是 $O(n + nlogk)$

由于在 $mod 5$ 的$5$中情况下 所有初始值转移到目标值的代价多少的排序并不是一样的

因此我们维护$5$个堆就好

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <queue>
 6 using namespace std;
 7 const int N = 2e5 + 10;
 8 const long long inf = 1e9;
 9 int a[N], dis[N * 5];
10 long long sum[5];
11 long long ans = 1e18;
12 int n, k, b, c, cnt;
13 priority_queue <long long> q[5];
14 int main()
15 {
16     scanf("%d%d%d%d", &n, &k, &b, &c);
17     b = min(b, c * 5);
18     for(int i = 1; i <= n; ++i)
19     {
20         scanf("%d", &a[i]);
21         for(int j = 0; j < 5; ++j)
22             dis[cnt++] = a[i] + j;
23     }
24     sort(a + 1, a + 1 + n);
25     sort(dis, dis + cnt);
26     cnt = unique(dis, dis + cnt) - dis;
27     int now = 1;
28     for(int i = 0; i < cnt; ++i)
29     {
30         int x = dis[i], kind =(inf + x) % 5;
31         long long cost;
32         while(now <= n && a[now] <= x)
33         {
34             for(int j = 0; j < 5; ++j)
35             {
36                 cost = (inf + j - a[now]) / 5 * b + (inf + j - a[now]) % 5 * c;
37                 q[j].push(cost);
38                 sum[j] += cost;
39                 if((int)q[j].size() > k)
40                 {
41                     sum[j] -= q[j].top();
42                     q[j].pop();
43                 }
44             }
45             ++now;
46         }
47         long long y = (inf + kind - x) / 5 * b * k;
48         if((int)q[kind].size() == k)
49             ans = min(ans, sum[kind] - y);
50     }
51     printf("%lld\n", ans);
52     return 0;
53 }
时间: 2024-10-11 12:16:51

codeforces 657C - Bear and Contribution [想法题]的相关文章

codeforces 584E Anton and Ira [想法题]

题意简述: 给定一个$1$到$n(n<=2000)$的初始排列以及最终排列 我们每次可以选取位置为$i$和$j$的 并交换它们的位置 花费为$ |i-j| $ 求从初始状态变换到末状态所需最小花费 ----------------------------------------------------------------------------------------------------------- 比赛时这题留了$40min$ 然而自己贪心策略还是有漏洞 结束后看了首页的官方题解 感

codeforces gym 100345I Segment Transformations [想法题]

题意简述 给定一个由A C G T四个字母组成的密码锁(每拨动一次 A变C C变G G变T T变A) 密码锁有n位 规定每次操作可以选取连续的一段拨动1~3次 问最少几次操作可以将初始状态变到末状态 并且把每次操作输出 (此题有spj) --------------------------------------------------------------------------------------------------------- 为了方便叙述 所有没有明确说明的位置均是在mod4

Codeforces 385C Bear and Prime Numbers(素数预处理)

Codeforces 385C Bear and Prime Numbers 其实不是多值得记录的一道题,通过快速打素数表,再做前缀和的预处理,使查询的复杂度变为O(1). 但是,我在统计数组中元素出现个数时使用了map,以至于后面做前缀和的累加时,每次都要对map进行查询,以至于TLE.而自己一直没有发现,以为是欧拉筛对于这道题还不够优,于是上网搜题解,发现别人的做法几乎一样,但是却能跑过,挣扎了许久才想起是map的原因.map的内部实现是一颗红黑树,每次查询的复杂度为O(logN),在本来时

Codeforces Round #634 (Div. 3) 补题

A. Candies and Two Sisters 签到题,直接输出即可 代码 #include<bits/stdc++.h> #define INF 0x3f3f3f3f typedef long long ll; using namespace std; inline void read(int &p) { p=0;int flag=1;char c=getchar(); while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} w

codeforces 680E Bear and Square Grid 巧妙暴力

这个题是个想法题 先预处理连通块,然后需要用到一种巧妙暴力,即0变1,1变0,一列列添加删除 复杂度O(n^3) #include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <queue> #include <algorithm> #includ

Codeforces Round #257 (Div. 2) E题:Jzzhu and Apples 模拟

E. Jzzhu and Apples time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Jzzhu has picked n apples from his big apple tree. All the apples are numbered from 1 to n. Now he wants to sell them to

POJ 2965 The Pilots Brothers&#39; refrigerator (想法题)

POJ 2965 题意: 输入一个形如: -+-- ---- ---- -+-- 4*4图案,+表示close,-表示open,定义一种操作为:改变某个单元格符号(+变-,-变+),同时单元格所在行与所在列的所有单元格符号都会发生改变. 求最少操作次数能使所有单元格内都是'-'.并输出要操作的单元格. 思路: 正常的做法和POJ 1573类似,dfs枚举即可,见code1. 这里提供一种高效的做法: 通过思考我们可以验证,某一个单元格内符号为'+',同时对其所在行与所在列的所有单元格进行操作(其

CodeForces 707A Brain&#39;s Photos (水题)

题意:给一张照片的像素,让你来确定是黑白的还是彩色的. 析:很简单么,如果有一种颜色不是黑白灰,那么就一定是彩色的. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #i

HDU 2410 Barbara Bennett&#39;s Wild Numbers (想法题)

题目链接:HDU 2410 Barbara Bennett's Wild Numbers 题意:给出两串数w,s(长度相同),第一串中有"?",问"?"取的值使w对应的数大于s对应的数 的最大方案数. 思路:W,S一一对应比较: 遇到第一个'?'之前比较情况 1.w[i]<s[i] 方案数0种:break: 2.w[i]>s[i] break.之后有n个''?' 方案数就有10的n次方种. 3.w[i]=s[i] 继续比较,重复1.2两个条件. 遇到'?