贪心做题笔记
CF1684D Traps
有
个数字 排成一排,你需要从左到右依次越过所有数。 两种越过
的方式:
- 花费
的代价越过; - 花费
的代价越过,后面的 都加 。 现在你拥有最多
次操作二的机会,求最小的代价总和。
。
一定会使用
假设这
- 本身的代价
变成了 ,收益增加 。 - 位置
中,除了位置 ,代价都会加一(因为它们在跳跃时代价都是 ),收益减少 。
综上,总收益为:
整理得:
显然我们希望让收益越大越好,所以我们得目标是最大化这个式子的值。
其中
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long LL;
typedef pair<int, int> PII;
struct FASTREAD {
template <typename T>
FASTREAD& operator >>(T& x) {
x = 0; bool flg = false; char c = getchar();
while (c < '0' || c > '9') flg |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
if (flg) x = -x; return *this;
}
template <typename T>
FASTREAD& operator >>(vector<T>& x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) >> *it;
return *this;
}
}fin;
struct FASTWRITE {
template <typename T>
FASTWRITE& operator <<(T x) {
if (x < 0) x = -x, putchar('-');
static int buf[35]; int top = 0;
do buf[top ++ ] = x % 10, x /= 10; while (x);
while (top) putchar(buf[ -- top] + '0');
return *this;
}
FASTWRITE& operator <<(char x) {
putchar(x); return *this;
}
template <typename T>
FASTWRITE& operator <<(vector<T> x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) << *it, putchar(' ');
putchar('\n');
return *this;
}
}fout;
const int N = 1e6 + 10;
const int P = 998244353;
int res;
void Luogu_UID_748509() {
int n, k; fin >> n >> k;
int res = 0;
vector<int> a(n); fin >> a;
for (int t : a) res += t;
res -= -n * k + k * k - k * (k - 1) / 2;
for (int i = 0; i < n; ++ i ) a[i] += i;
sort(a.begin(), a.end(), greater<int>());
for (int i = 0; i < k; ++ i ) res -= a[i];
fout << res << '\n';
return;
}
signed main() {
int Testcases = 1;
fin >> Testcases;
while (Testcases -- ) Luogu_UID_748509();
return 0;
}
CF1029E Tree with Small Distances
给定一颗
个节点的树,以 为根。 求最少在树中加几条边,使得任意一点到
的距离均小于等于 。
。
不难发现最优策略中,每条加的边都有端点
第一步,最自然的想法就是将
接下来上一步的点就不需要考虑了。我们要做的仍然是连接
实现上,我们可以维护大根堆,以节点的深度从大到小排序。每次取出堆顶即可。
#include <bits/stdc++.h>
using namespace std;
//#define int long long
typedef long long ll;
typedef unsigned long long LL;
typedef pair<int, int> PII;
struct FASTREAD {
template <typename T>
FASTREAD& operator >>(T& x) {
x = 0; bool flg = false; char c = getchar();
while (c < '0' || c > '9') flg |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
if (flg) x = -x; return *this;
}
template <typename T>
FASTREAD& operator >>(vector<T>& x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) >> *it;
return *this;
}
}fin;
struct FASTWRITE {
template <typename T>
FASTWRITE& operator <<(T x) {
if (x < 0) x = -x, putchar('-');
static int buf[35]; int top = 0;
do buf[top ++ ] = x % 10, x /= 10; while (x);
while (top) putchar(buf[ -- top] + '0');
return *this;
}
FASTWRITE& operator <<(char x) {
putchar(x); return *this;
}
template <typename T>
FASTWRITE& operator <<(vector<T> x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) << *it, putchar(' ');
putchar('\n');
return *this;
}
}fout;
const int N = 1e6 + 10;
const int P = 998244353;
int n;
vector<int> g[N];
int dep[N];
bool st[N];
int fa[N];
void dfs(int u, int f) {
fa[u] = f;
for (int v : g[u]) if (v != f) {
dep[v] = dep[u] + 1;
dfs(v, u);
}
return;
}
void Luogu_UID_748509() {
fin >> n;
for (int i = 1; i < n; ++ i ) {
int x, y; fin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dep[1] = 1;
int res = 0;
dfs(1, -1);
priority_queue<PII> q;
for (int i = 1; i <= n; ++ i ) if (dep[i] > 3) q.push({dep[i], i});
while (q.size()) {
int u = q.top().second; q.pop();
if (st[u]) continue;
u = fa[u];
st[u] = true;
for (int v : g[u]) {
st[v] = true;
}
++ res;
}
fout << res;
}
signed main() {
int Testcases = 1;
// fin >> Testcases;
while (Testcases -- ) Luogu_UID_748509();
return 0;
}
CF1197C Array Splitting
- 给出一个长度为
的严格单调增的序列,将其分成 段,使得每一段的极差的和最小,求这个最小的和。 。
推式子。
若这
整理一下,把
其中
#include <bits/stdc++.h>
using namespace std;
//#define int long long
typedef long long ll;
typedef unsigned long long LL;
typedef pair<int, int> PII;
struct FASTREAD {
template <typename T>
FASTREAD& operator >>(T& x) {
x = 0; bool flg = false; char c = getchar();
while (c < '0' || c > '9') flg |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
if (flg) x = -x; return *this;
}
template <typename T>
FASTREAD& operator >>(vector<T>& x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) >> *it;
return *this;
}
}fin;
struct FASTWRITE {
template <typename T>
FASTWRITE& operator <<(T x) {
if (x < 0) x = -x, putchar('-');
static int buf[35]; int top = 0;
do buf[top ++ ] = x % 10, x /= 10; while (x);
while (top) putchar(buf[ -- top] + '0');
return *this;
}
FASTWRITE& operator <<(char x) {
putchar(x); return *this;
}
template <typename T>
FASTWRITE& operator <<(vector<T> x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) << *it, putchar(' ');
putchar('\n');
return *this;
}
}fout;
const int N = 1e6 + 10;
const int P = 998244353;
int a[N], d[N];
void Luogu_UID_748509() {
int n, k; fin >> n >> k;
for (int i = 1; i <= n; ++ i ) {
fin >> a[i];
d[i] = a[i - 1] - a[i];
}
sort(d + 2, d + n + 1);
int res = a[n] - a[1];
for (int i = 2; i <= k; ++ i ) res += d[i];
fout << res;
}
signed main() {
int Testcases = 1;
// fin >> Testcases;
while (Testcases -- ) Luogu_UID_748509();
return 0;
}
CF1038D Slime
- 给定
个数 。每次可以选择两个相邻的 将其合并为 或 。求 次操作后的数的最大值。 。
多手玩几组可以发现,最终的答案一定是对每个
所以我们可以对于每个负数乘
注意会有一个问题。将每个
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long LL;
typedef pair<int, int> PII;
struct FASTREAD {
template <typename T>
FASTREAD& operator >>(T& x) {
x = 0; bool flg = false; char c = getchar();
while (c < '0' || c > '9') flg |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
if (flg) x = -x; return *this;
}
template <typename T>
FASTREAD& operator >>(vector<T>& x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) >> *it;
return *this;
}
}fin;
struct FASTWRITE {
template <typename T>
FASTWRITE& operator <<(T x) {
if (x < 0) x = -x, putchar('-');
static int buf[35]; int top = 0;
do buf[top ++ ] = x % 10, x /= 10; while (x);
while (top) putchar(buf[ -- top] + '0');
return *this;
}
FASTWRITE& operator <<(char x) {
putchar(x); return *this;
}
template <typename T>
FASTWRITE& operator <<(vector<T> x) {
for (auto it = x.begin(); it != x.end(); ++ it ) (*this) << *it, putchar(' ');
putchar('\n');
return *this;
}
}fout;
const int N = 1e6 + 10;
const int P = 998244353;
void Luogu_UID_748509() {
int n, res = 0; fin >> n;
vector<int> a(n); fin >> a;
if (n == 1) {
fout << a[0];
return;
}
sort(a.begin(), a.end());
int mn = a[0], mx = a[n - 1];
if (mn >= 0) {
res = -a[0];
for (int i = 1; i < n; ++ i ) res += a[i];
}
else if (mx <= 0) {
res = a[n - 1];
for (int i = 0; i + 1 < n; ++ i ) res -= a[i];
}
else {
for (int t : a) res += abs(t);
}
fout << res;
return;
}
signed main() {
int Testcases = 1;
// fin >> Testcases;
while (Testcases -- ) Luogu_UID_748509();
return 0;
}
CF804A Find Amir
- 有一张
个节点的完全图,其中连接 两点的边的边权为 。求走完所有城市所需的最小花费(起点任选)。 。
方案是
所以答案为边数的一半,即
#include <bits/stdc++.h>
using namespace std;
int main() {
int n; cin >> n;
cout << (n - 1) / 2;
}
给定
个区间 。若将所有有交集的区间合并,最后有多少区间。
按
枚举
- 如果
:合并。实现上就是 不变, 。 - 如果
:重开。实现上就是 , 。
给定
个区间 。 给定
个人,每个人有一个区间 和 。 如果
被 包含,那么第 个人就可以选择区间 。 每个区间至多被一个人选择,每个人至多选
个区间。 求是否所有区间都能被某个人选中。
把区间和人放在一起,并全部以左端点排序。左端点相同时把人排在前面。
然后按顺序枚举
; 。
由于我们是按
此时如果有多个满足条件的人,那么我们应该贪心地找右端点最小的,也就是找
实现上维护 set
。枚举到人时加入 set
。
给定长度为
的序列 。 对于一个
,选择 的代价为 。 给定代价之和的上限
。求一个 ,使得选择的 最多。
可以发现,如果将
若确定了区间
枚举左端点
同时可以发现随着
给定长度为
的序列 。 至多
次操作,每次可以将一个大于 的 减一。 你需要进行若干次操作后,使得存在
,且 最小。 求这个最小值。
二分答案
先从左往右调整
然后枚举
也就是说在
可以发现随着
给定
个区间 。 你需要选择
个区间,使得它们至少有一个公共点且区间长度的极差最小。
如果有若干个区间被选中,那么如果其中有
我们首先按照区间长度从小到大排序。然后枚举最小长度
找这个
给定长度为
的仅含 的字符串。 你可以改变至多
个字符,求改变后最大的连续相同字符的数量。
二分答案
也可以双指针。假设我们要全变成
给定长度为
的序列 。 定义
表示区间 内不同元素的数量。 随机选取
,求 的期望。
一个区间内相同的元素只会对答案产生一次贡献。不妨将这次贡献放在最左面的元素上。
考虑这个问题:第
显然需要满足两个条件:
; 。
那么答案即
于是统计每个元素在它之前最后一次出现的位置。然后根据上述公式累加答案即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!