CF 1425 - E. Excitation of Atoms

2023-11-04 01:31
文章标签 cf 1425 excitation atoms

本文主要是介绍CF 1425 - E. Excitation of Atoms,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接


题意:

n n n 个原子。每个原子有两种状态,静态和激发态。每个原子 i i i 从静态转换到激发态需要消耗 d [ i ] d[i] d[i] 的能量,而在激发态会贡献的 a [ i ] a[i] a[i] 的能量。初始的时候,序号从 1 − n 1-n 1n 的原子是按照编号顺序连接在一起的,也就是原子 i i i 连接到原子 i + 1 i + 1 i+1。在激发原子时有一个连锁反应,就是被激发的原子会自动激发它连接的下一个原子,这个时候是不会消耗能量的。但是最后一个原子不能连接到任何一个原子。

给定 K K K,我们必须要改变 K K K 个连接关系。有一个限定是不能连接到自己,也不能连接到原来连接的原子。比如初始时,原子 a a a 连接到原子 b b b,那么我们改变这个连接关系时,原子 a a a 不能连接到原子 a a a,也不能再次连接原子 b b b

我们可以选择激发任意多个原子,问最终能得到最大的能量是多少。


思路:

1)当 K > = 2 K>=2 K>=2
①我们总是能将所有原子全部激发。我们可以选择激发前 N − 1 N-1 N1 个原子中(因为最后一个原子不能连接到任何的原子,所以不能作为激发原子)能量消耗 d [ i ] d[i] d[i] 最小的那个原子 i i i 以激发所有的原子。这样我们的收益就是:所有原子的能量和 - 原子 i i i 能量消耗。
在这里插入图片描述

②我们还可以选择不改变原子的连接关系(虽然我们必须改变K次,但是我们可以改变了再改变回去哈哈哈),然后遍历激发每一个原子 i i i, 取(后缀能量和 - 当前原子消耗)的最大收益 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i])

2)当 K = = 0 K == 0 K==0
就只能不改变原来原子的连接关系,然后取 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i])

3)当 K = = 1 K == 1 K==1

第一种情况:

我们枚举断点 i i i, 断掉从点 i i i 发出的边,然后将点 i i i 连接到第一个点上(从2开始枚举,因为原子1不能连接到原子1)。然后这个原子就变成了两个部分: ① [ 1 , i ] [1, i] [1,i] 的环; ② [ i + 1 , N ] [i + 1, N] [i+1,N] 的链。
在这里插入图片描述

对于第一个部分,就和 K > = 2 K>=2 K>=2 时的第一种情况类似,区间能量和-最小能量消耗即可。
对于第二个部分,就和 K > = 2 K>=2 K>=2 时的第二种情况类似,直接找到 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i]) 即可。
最后的结果自然就是两个部分相加了。

第二种情况:
我们枚举断点 i i i, 断掉从点 i − 1 i - 1 i1 连接到 i i i 的边,并且连接到 i + 1 i + 1 i+1 上。这样我们就成了一个如下图所示的样子。
在这里插入图片描述
这样的话我们考虑激发点在断点 i i i [ 1 , i − 1 ] [1, i - 1] [1,i1],还是在其后 [ i , N ] [i, N] [i,N]

如果在断点后,那就很简单就是像 K > = 2 K>=2 K>=2 时的第二种情况,直接找到 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i]) 即可。

如果在断点前,我们就需要找到 [ 1 , i − 1 ] [1, i - 1] [1,i1] 这个区间内的 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i]) ,然后减去 a [ i ] a[i] a[i]。所以我们可以用线段树维护区间的 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i]) 。这个时候需要考虑单独的结点 i i i 是不是有贡献,如果有正的贡献就加上。

最后的结果自然是激发点取断点前和断点后的最大值。

【关于为什么只间隔一个点呢,对于在断点后激发无影响。但是对于在断点前激发,那么断点后的能量和是确定的,我们对比的实际上是断点前那一段的 m a x ( s u f f i x [ i ] − d [ i ] ) max(suffix[ i ] - d[ i ]) max(suffix[i]d[i]) 。所以去掉更多的点,显然不是更优的策略。】

tips!!!

对于每种情况都必须考虑不激发的情况,也就是每种情况的结果都要和 0 0 0 对比取最大值。


Code:

#include <bits/stdc++.h>#define MID (l + r) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll ;ll read() {ll res = 0, f = 1; char ch = getchar();while(ch < '0' || ch > '9') { if(ch == '-') f = -f; ch = getchar(); }while(ch >= '0' && ch <= '9') { res = res * 10 + ch - '0'; ch = getchar(); }return res * f;
}
const int maxN = 100005;int N, K;
int a[maxN], d[maxN];
ll prefix[maxN];
ll _min[maxN];
ll dp[maxN]; //后缀
ll tree[maxN << 2];
void pushup(int rt) {tree[rt] = max(tree[lsn], tree[rsn]);
}
void build_tree(int rt, int l, int r) {if(l == r) {tree[rt] = prefix[N] - prefix[l - 1] - d[l];return ;}int mid = MID;build_tree(Lson);build_tree(Rson);pushup(rt);
}
ll query(int rt, int l, int r, int ql, int qr) {if(ql <= l && qr >= r) {return tree[rt];}int mid = MID;if(qr <= mid) return query(QL);if(ql > mid) return query(QR);return max(query(QL), query(QR));
}
int main () {N = read(), K = read();for(int i = 1; i <= N; ++ i ) { //收益a[i] = read();prefix[i] = prefix[i - 1] + (ll)a[i];}for(int i = 1; i <= N; ++ i ) { //消耗d[i] = read();}ll MIN = d[1], min_pos = 1;_min[1] = min_pos;for(int i = 2; i < N; ++ i) {if(d[i] < MIN) {MIN = d[i];min_pos = i;}_min[i] = min_pos;}dp[N + 1] = -INF;for(int i = N; i >= 1; -- i ) {dp[i] = max(dp[i + 1], prefix[N] - prefix[i - 1] - (ll)d[i]);}build_tree(1, 1, N);ll ans = 0;if(K >= 2){ans = max(ans, prefix[N] - d[_min[N - 1]]);ans = max(ans, dp[1]);} else if(K == 0) {ans = max(ans, dp[1]);} else {//连向第一个点for(int i = 2; i < N; ++ i ) {ll fir = prefix[i] - d[_min[i]]; if(fir < 0) fir = 0;ll sec = dp[i + 1]; if(sec < 0) sec = 0;ans = max(ans, fir + sec);}//连向后面的点for(int i = 2; i < N; ++ i ) { //枚举断点i,跳过i点 割掉i - 1到i的边,ll left = max(query(1, 1, N, 1, i - 1) - (ll)a[i] + max(0ll, ll(a[i] - d[i])), 0ll); //从断点前激发ll right = max(0ll, dp[i]); //从断点后激发ans = max(left, ans);ans = max(right, ans);}}cout << ans << endl;return 0;
}
/*
4 1
2 5 2 1
101 2 101 100ans: 74 0
5 3 2 2
13 8 5 1ans: 14 1
10 10 9 100
1 10 10 1000000ans: 119*/

这篇关于CF 1425 - E. Excitation of Atoms的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/342286

相关文章

cf 164 C 费用流

给你n个任务,k个机器,n个任务的起始时间,持续时间,完成任务的获利 每个机器可以完成任何一项任务,但是同一时刻只能完成一项任务,一旦某台机器在完成某项任务时,直到任务结束,这台机器都不能去做其他任务 最后问你当获利最大时,应该安排那些机器工作,即输出方案 具体建图方法: 新建源汇S T‘ 对任务按照起始时间s按升序排序 拆点: u 向 u'连一条边 容量为 1 费用为 -c,

CF 508C

点击打开链接 import java.util.Arrays;import java.util.Scanner;public class Main {public static void main(String [] args){new Solve().run() ;} }class Solve{int bit[] = new int[608] ;int l

【CF】C. Glass Carving(二分 + 树状数组 + 优先队列 + 数组计数)

这题简直蛋疼死。。。。。 A了一下午 #include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int maxn = 200005;int h,w,n;int C1[maxn],C2[maxn];int

【CF】E. Anya and Cubes(双向DFS)

根据题意的话每次递归分3种情况 一共最多25个数,时间复杂度为3^25,太大了 我们可以分2次求解第一次求一半的结果,也就是25/2 = 12,记录结果 之后利用剩余的一半求结果 s-结果 = 之前记录过的结果 就可以 时间复杂度降低为 3 ^ (n/2+1) 题目链接:http://codeforces.com/contest/525/problem/E #include<set

【CF】D. Arthur and Walls(BFS + 贪心)

D题 解题思路就是每次检查2X2的方格里是否只有一个‘*’,如果有的话这个*就需要变成‘.’,利用BFS进行遍历,入队的要求是这个点为. 一开始将所有的'.'全部加入队列,如果碰到一个'*'变成'.'就入队,判断的时候从4个方向就行判断 题目链接:http://codeforces.com/contest/525/problem/D #include<cstdio>#include<

CF#271 (Div. 2) D.(dp)

D. Flowers time limit per test 1.5 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/474/problem/D We s

CF Bayan 2015 Contest Warm Up B.(dfs+暴力)

B. Strongly Connected City time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/475/probl

CF Bayan 2015 Contest Warm Up A.(模拟+预处理)

A. Bayan Bus time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/475/problem/A The fi

CF #278 (Div. 2) B.(暴力枚举+推导公式+数学构造)

B. Candy Boxes time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/B There

CF#278 (Div. 2) A.(暴力枚举)

A. Giga Tower time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/A Giga To