题目链接:Here

题意:把 \(n\) 个数变成 \(k\) 个相同的数,每次可以把 \(n\) 个数里最大的 \(-1\) 或最小的 \(+1\) ,问最小改变次数

思路:

我们可以枚举,把 \(n\) 个数变成 \(k\) 个 \(a[i]\) (这个相同的数一定是数组里的数,因为如果不是,那么改变次数一定会比正常多)

如果相同的数大于 \(k\) 个,那么改变次数为 \(0\) ,特判掉

有三种情况,一种是只动前面,一种只动后面,还有就是前后都动

因为是改变最大或最小的数,所以我们只有把所有小于 \(a[i]\) 的数变成 \(a[i]-1\) (或者大于 \(a[i]\) 的数变成\(a[i]+1\) )才能进行下一次的改变

然后接着考虑,在什么情况下可以动前面呢,当然是他前面的数大于\((k-1)\)个,同理,在他后面的数大于 \((k-1)\) 个时才可以动后面,然后在任何情况下都可以前后都动( 在$(i=1) $时就相当于是动后面结果不冲突)

以只动前面为例

\(tem1 = (\sum\limits_{j=1}^i((a[i] - 1) -a[j]) + k\)

化简一下发现

\(tem1 = \sum\limits_{j=1}^i(a[i] - 1) -\sum\limits_{j=1}^ia[j] + k\)​

就是 \(i*(a[i]-1)-a[i]\) 的前缀和 \(+k\) ,提前搞一个前缀和可以降低时间复杂度

只动后面同理

\(tmp2 = \sum\limits_{j=i}^na[i] -\sum\limits_{j=i}^n(a[j] + 1) + k\)

动两边,这时相等的数的个数恰好为 \(n\) ,把他们都搞成 \(a[i]\) 然后再减掉多余的

\(tmp3 = \sum\limits_{j=i}^na[j] - \sum\limits_{j=1}^ia[j] + \sum\limits_{j=1}^ia[i] - \sum\limits_{j=i}^na[i] - (n - k)\)

记录好前缀和 和(后缀和?)就可以用 \(\mathcal{O}(n)\)​ 的复杂度解决掉这个问题了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll inf = 1e17;
ll a[200009];
ll cnt[200009];
ll sumq[200009], sumh[200009];
int main() {
int n, k;
ll ans = inf;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) sumq[i] = sumq[i - 1] + a[i];
for (int i = n; i >= 1; i--) sumh[i] = sumh[i + 1] + a[i];
for (int i = 1; i <= n; i++) {
if (a[i] == a[i - 1])cnt[i] = cnt[i - 1] + 1;
else cnt[i] = 1;
if (cnt[i] >= k) {
puts("0");
return 0;
}
}
for (int i = 1; i <= n; i++) {
if (i >= k) {
ll tem1 = i * (a[i] - 1) - sumq[i] + k;
ans = min(tem1, ans);
}
if (n - i + 1 >= k) {
ll tem2 = n - i + 1;
tem2 = sumh[i] - tem2 * (a[i] + 1) + k;
ans = min(tem2, ans);
}
if (i < k && (n - i + 1) < k) {
ll tem3 = i * a[i] - sumq[i] + sumh[i] - (n - i + 1) * a[i] - (n - k);
ans = min(tem3, ans);
}
}
printf("%lld\n", ans);
return 0;
}

便捷写法

int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, k;
cin >> n >> k;
vector<ll> a(n);
for (ll &x : a) cin >> x;
sort(a.begin(), a.end());
for (int i = 0; i + k - 1 < n; ++i) {
if (a[i] == a[i + k - 1])
return printf("0\n"), 0;
} ll lcost = 0;
ll rcost = 0;
for (int i = 0; i < k; ++i) {
lcost += a[k - 1] - a[i];
rcost += a[n - 1 - i] - a[n - k];
}
for (int j = k; j < n; ++j) {
if (a[k - 1] == a[j]) lcost--;
if (a[n - k] == a[n - 1 - j]) rcost--;
}
ll sum = 0;
for (int i = 0; i < n - 1 - i; ++i) sum += a[n - 1 - i] - a[i];
ll ans = min(sum - (n - k), min(lcost, rcost));
cout << ans;
}

题解 | CF1328F. Make k Equal (思维,前缀 & 后缀和)的更多相关文章

  1. [JZOJ5280]膜法师题解--思维+前缀和

    [JZOJ5280]膜法师题解--思维+前缀和 题目链接 暴 力 过 于

  2. Codeforces Round #320 (Div. 2) [Bayan Thanks-Round] D "Or" Game 枚举+前缀后缀

                                                                            D. "Or" Game       ...

  3. POJ 2752 (KMP 所有可能长度的前缀后缀) Seek the Name, Seek the Fame

    题意: 求一个字符串的相同前缀后缀的所有可能的长度,这里该字符串其本身也算自己的前缀和后缀. 分析: 我们知道next数组的性质是,该字符之前的字符串的最大相同前缀后缀. 既然知道了最大的,即next ...

  4. hdoj 2594 Simpsons’ Hidden Talents 【KMP】【求串的最长公共前缀后缀】

    Simpsons' Hidden Talents Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

  5. CF-1328 F. Make k Equal

    F. Make k Equal 题目链接 题意 长度为n的序列,每次可以选择一个最大的数字将其减一或者选择一个最小的数字将其加一,问最少操作多少次可以使得序列中至少存在 k 个一样的数字 分析 官方题 ...

  6. k倍区间 前缀和【蓝桥杯2017 C/C++ B组】

    标题: k倍区间 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍 ...

  7. 1280 前缀后缀集合(map)

    1280 前缀后缀集合 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 一个数组包含N个正整数,其中有些是重复的.一个前缀后缀集是满足 ...

  8. kuangbin专题七 HDU1540 Tunnel Warfare (前缀后缀线段树)

    During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast a ...

  9. jQuery EasyUI/TopJUI基本的数字输入框(保留两位小数,带前缀后缀...)

    jQuery EasyUI/TopJUI基本的数字输入框(保留两位小数,带前缀后缀...) numberbox(数值输入框) HTML required:必填字段,默认为false:prompt:显示 ...

  10. 求x!在k进制下后缀零的个数(洛谷月赛T1)

    求x!在k进制下后缀和的个数 20分:     求十进制下的x!后缀和的个数 40分: 高精求阶乘,直接模拟过程 (我不管反正我不打,本蒟蒻最讨厌高精了) 60分     利用一个定理(网上有求x!在 ...

随机推荐

  1. java中Calendar日历类型常见方法

    Calendar是Java中常用的时间处理工具之一,它提供了很多日历类型常见方法,下面是一些常用的方法及对应的代码和运行结果. 1. 如何创建 Calendar 日历对象 Calendar 是一个抽象 ...

  2. Mysql数据库插入数据时出现Unknown column ‘admin‘ in ‘field list‘错误

    报错内容 报错原因 字段和插入的值所用的引号不对 解决方案 insert into t_user(`username`,`password`,`email`) VALUES(`admin`,`admi ...

  3. 【JSOI2008】火星人 (哈希+Splay)

    题目 这种含有修改操作的就难以用后缀数组实现了,求LCP这种区间相等的类型可以想到用hash判断,同时LCP的答案大小符合二分条件可以二分求出,如果只有修改可以用线段树维护,因为还有有插入操作所以想到 ...

  4. 基于 Echarts实现可视化数据大屏展示?

    当涉及到使用Echarts实现可视化数据大屏展示时,以下是一份非常详细的介绍说明. 第一部分:介绍Echarts Echarts是一个由百度开源的基于JavaScript的可视化图表库.它支持多种图表 ...

  5. HTML中的常用的特殊字符以及所有特殊字符

    ## HTML常用特殊字符以下是HTML中常用的特殊符号及其编码: | 特殊符号 | 编码 | 描述 || --- | --- | --- || `<` | `&lt;` | 小于号 | ...

  6. 当数字孪生系统接入CesiumJS,将为智慧城市项目带来怎样的改变?

    数字孪生系统接入CesiumJS的契机,正是智慧城市项目的需要.因为许多智慧城市项目中包含了大量地形.倾斜摄影.DOM.DEM等GIS数据,那么为了能够在数字孪生系统中导入这些GIS数据,同时让这些数 ...

  7. 【笔记】Ribbon负载均衡伪随机算法

    伪随机:思路 当一个下标(伪服务)连接被调用两次,第三次如果还是它,就让再随机一次 当重复随机到一台服务两次时判断第三次是否还是它 是的话 我们要进行 再次随机 也就是第三次 package top. ...

  8. Ef Core花里胡哨系列(10) 动态起来的 DbContext

    Ef Core花里胡哨系列(10) 动态起来的 DbContext 我们知道,DbContext有两种托管方式,一种是AddDbContext和AddDbContextFactory,但是呢他们各有优 ...

  9. SQLServer清空数据库日志

    -------SQl2008以上 清空日志-------- USE[master] GO ALTER DATABASE [数据库名称] SET RECOVERY SIMPLE WITH NO_WAIT ...

  10. Luogu P1298 最接近的分数 做题记录

    算是水紫,不过也学到一些有用的东西. 题意 给定正小数 \(N\).求分子不大于 \(n\),分母不大于 \(m\) 的分数 \(\dfrac{n}{m}\),使得 \(\dfrac{n}{m}\) ...