CF433C Ryouko's Memory Note(贪心)题解

题意

给出2个正整数 n,m(1n,m105)与长度为m的序列a[1m],保证a[i]n,你可以把所有值为a[i]的元素改为a[j],可以不改且只能改一次,要求最小化i=1im1|aiai+1|

算法

贪心,暴力枚举

思路

首先要知道一个结论:

a为序列b的中位数时,i=1in|abi|最小。

放到这个题目里,对于每一个元素a[i],序列b就是与它相邻且不相等的元素集合。所以,我们可以统计出与每一个相邻的数,排序之后用中位数计算对答案的贡献。

由于每一个数最多被枚举了2遍,所以总复杂度为O(2mlogm)

具体实现请看代码。

参考代码

copy
#include <cstdio> #include <algorithm> #include <vector> #define LL long long using namespace std; const int maxn = 1e5 + 10; int n,a[maxn],m; LL Ans = 0; vector<int> v[maxn]; int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++ i) scanf("%d", a + i); for(int i = 1; i <= m; ++ i){ if(a[i] != a[i - 1] && i != 1) v[a[i]].push_back(a[i - 1]); if(a[i] != a[i + 1] && i != m) v[a[i]].push_back(a[i + 1]); if(i != 1) Ans += abs(a[i] - a[i - 1]); //先处理出初始答案 } LL ls = Ans; for(int i = 1; i <= n; ++ i){ int len = v[i].size(); if(!len) continue; sort(v[i].begin(), v[i].end()); int pos = v[i][len / 2]; LL ret = ls; for(int j = 0; j < len; ++ j){ ret -= abs(i - v[i][j]); ret += abs(pos - v[i][j]); //计算更改后的答案 } Ans = min(Ans, ret); } printf("%lld\n", Ans); return 0; }
posted @   When_C  阅读(139)  评论(0编辑  收藏  举报
编辑推荐:
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
阅读排行:
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· 软件产品开发中常见的10个问题及处理方法
· Vite CVE-2025-30208 安全漏洞
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· MQ 如何保证数据一致性?
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起