Codeforces Round #775 - F. Serious Business

news/2024/11/24 1:37:59/

F. Serious Business

prob. :有 3 × n 3\times n 3×n个格子,每个格子有一个权值,你要从左上走到右下,每一步只能往右或往下走,刚开始的时候第二行是封锁的状态,你有一些可选的操作去解锁第二行从 [ L i , R i ] [L_i, R_i] [Li,Ri]的格子,每种操作的代价分别是 k i k_i ki, 问最大能获得的值是多少

ideas :非常巧妙将三行的权值拆成两个函数

pref表示每行的前缀和

s [ i ] = p r e f [ 0 ] [ i + 1 ] − p r e f [ 1 ] [ i ] s[i] = pref[0][i +1] - pref[1][i] s[i]=pref[0][i+1]pref[1][i]

f [ i ] = p r e f [ 1 ] [ i + 1 ] − p r e f [ 2 ] [ i ] + p r e f [ 2 ] [ n ] f[i] = pref[1][i + 1] - pref[2][i] + pref[2][n] f[i]=pref[1][i+1]pref[2][i]+pref[2][n]

最终的答案变成 m a x 0 ≤ i < j < n s [ i ] + f [ j ] − c o s t ( i , j ) max_{0\le i < j < n} s[i] + f[j] -cost(i, j) max0i<j<ns[i]+f[j]cost(i,j), cost指第二行解锁区间 [ i , j ] [i, j] [i,j]的最小价值

// 在下面具体代码实现的时候s和f的+1-1可能和上述有些不同
在这里插入图片描述

直接用s+f更新答案是只解锁一个区间时候的答案,dp记录的是多个区间时候的答案(这里为了少转移只对每个操作的r端点更新值

dp是s-cost,对于每个操作 L i , R i L_i, R_i Li,Ri,用s和dp更新 d p [ R ] dp[R] dp[R], 对应的s是 [ L , R ] [L, R] [L,R]区间的因为他还在第0行没有走下来,dp已经在第1行了,所以是由 [ L − 1 , R − 1 ] [L-1, R-1] [L1,R1]转移的,(R这里不用算进去但可能算进去也没啥区别,因为-k之后肯定比本身小)

注意更新dp的时候要对区间排序

写死我了,我好菜啊,谢谢npy帮我debug,“有些人被迫参与全程”

#include <bits/stdc++.h>using namespace std;typedef long long ll;
const ll N = 5e5 + 50;
const ll inf = 0x3f3f3f3f3f3f3f3f;struct node {ll l, r;ll s, f, sf;
};node tr[N << 2];ll s[N], f[N], dp[N];void pushup(ll u) {tr[u].s = max(tr[u << 1].s, tr[u << 1 | 1].s);tr[u].f = max(tr[u << 1].f, tr[u << 1 | 1].f);tr[u].sf = max(max(tr[u << 1].sf, tr[u << 1 | 1].sf), tr[u << 1].s + tr[u << 1 | 1].f);
}void build(ll u, ll l, ll r) {if (l == r) {tr[u] = {l, r, s[l], f[l], s[l] + f[l]};} else {tr[u] = {l, r, -inf, -inf, -inf};ll mid = (l + r) >> 1;build(u << 1, l, mid);build(u << 1 | 1, mid + 1, r);pushup(u);}
}void modify(ll u, ll l, ll r, ll s) {if (tr[u].l >= l && tr[u].r <= r) {tr[u].s = max(tr[u].s, s);tr[u].sf = tr[u].s + tr[u].f;return;}ll mid = (tr[u].l + tr[u].r) >> 1;if (l <= mid) modify(u << 1, l, r, s);if (r > mid) modify(u << 1 | 1, l, r, s);pushup(u);
}struct note {ll sf, s, f;
};note querySF(ll u, ll l, ll r) {if (tr[u].l >= l && tr[u].r <= r) {return {tr[u].sf, tr[u].s, tr[u].f};}ll mid = (tr[u].l + tr[u].r) >> 1;ll ansSF = -inf, ansS = -inf, ansF = -inf, ss = -inf, ff = -inf;if (l <= mid) {auto tmp = querySF(u << 1, l, r);ansSF = max(ansSF, tmp.sf);ansS = max(ansS, tmp.s);ansF = max(ansF, tmp.f);ss = max(ss, tmp.s);}if (r > mid) {auto tmp = querySF(u << 1 | 1, l, r);ansSF = max(ansSF, tmp.sf);ansS = max(ansS, tmp.s);ansF = max(ansF, tmp.f);ff = max(ff, tmp.f);}ansSF = max(ansSF, ss + ff);return {ansSF, ansS, ansF};
}ll a[5][N];
ll pref[5][N];struct seg {ll l, r;ll k;
};seg segs[N];signed main() {ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);ll n, q;cin >> n >> q;bool checkflag = 0;for (ll i = 0; i < 3; ++i) {for (ll j = 1; j <= n; ++j) {cin >> a[i][j];if (a[i][j] > 0) checkflag = 1;pref[i][j] = pref[i][j - 1] + a[i][j];}}for (ll i = 1; i <= n; ++i) {s[i] = pref[0][i] - pref[1][i - 1];f[i] = pref[1][i] - pref[2][i - 1] + pref[2][n];}build(1, 1, n + 5);for (ll i = 0; i <= n; ++i) dp[i] = -inf; // init dpll ans = -inf;for (ll i = 1; i <= q; ++i) { // refresh dp by scin >> segs[i].l >> segs[i].r >> segs[i].k;ll l = segs[i].l, r = segs[i].r;ll k = segs[i].k;ans = max(ans, querySF(1, l, r).sf - k);ll tmp = querySF(1, l, r).s - k;dp[r] = max(tmp, dp[r]);}for (ll i = 0; i <= n; ++i) s[i] = dp[i];build(1, 1, n + 5);sort(segs + 1, segs + q + 1, [&](auto a, auto b) {return a.r < b.r;});for (ll i = 1; i <= q; ++i) { // refresh dp by dpll l = segs[i].l, r = segs[i].r;ll k = segs[i].k;ll tmp = querySF(1, (l - 1 == 0 ? l : l - 1), (r - 1 == 0 ? r : r - 1)).s - k;modify(1, r, r, tmp);ans = max(ans, querySF(1, (l - 1 == 0 ? l : l - 1), r).sf - k);}cout << ans << endl;return 0;
}

http://www.ppmy.cn/news/361601.html

相关文章

Codeforces Round #775 CF1649 ABCD

1649A - Game(英语题) 不能走0&#xff0c;最小跳跃长度 题目描述很微妙&#xff0c;注意只能跳一次&#xff01;我开始以为是遇到连续 0 0 0才跳&#xff0c;后来感谢EM-LGH大神&#xff0c;才让我悟到了正确题意。 1649B - Game of Ball Passing(贪心) 传球游戏&#xff0c;…

Codeforces Round #775 (Div. 2) E.Tyler and Strings

Problem - E - Codeforces 题意&#xff1a;给你两个数组s、t&#xff0c;让你重新排列s的数&#xff0c;问有多少种排列使得s的字典序严格小于t。s&#xff0c;t的长度和数组内的数开到2e5。 首先先得知道多重集的排列数&#xff1a; 一个由c1个a1&#xff0c;c2个a2……ck…

Codeforces Round #775 (Div. 2, based on Moscow Open Olympiad in Informatics) 题解

A. Game 思路 只能跳一次&#xff01;&#xff01;&#xff01;&#xff01;从左和从右开始找到第一个0&#xff0c;然后相减2&#xff08;从0回到上一格的1陆地&#xff09;即可 经验教训 无 AC代码 #define int long long const int maxn 2e5 10; int a[maxn];void solve(…

LeetCode-775. 全局倒置与局部倒置【最小后缀,归纳】

LeetCode-775. 全局倒置与局部倒置【最小后缀&#xff0c;归纳】 题目描述&#xff1a;解题思路一&#xff1a;常规暴力方法剪枝。解题思路二&#xff1a;维护后缀最小值.解题思路三&#xff1a;三行代码&#xff01;&#xff01;&#xff01;进一步&#xff0c;我们可以发现对…

Codeforces Round #775 (Div. 2, based on Moscow Open Olympiad in Informatics)A~C 题解(原来如此简单,超级详细入门必备)

A. Game 题目传送门 题目理解&#xff1a;一个人要过河&#xff0c;这个人不会游泳&#xff0c;只能走陆地&#xff0c;一旦碰水就死翘翘&#xff0c;但是现在给你一个bug&#xff0c;只要你给x个硬币&#xff0c;你就可以传送到ix块陆地上面&#xff0c;比如你在第5块土地上…

linux 775和777权限有什么区别

读取权限 r 4 写入权限 w 2 执行权限 x 1 775 这三个数字代表拥有者&#xff0c;组用户&#xff0c;其他用户的权限。 例如&#xff1a; 7 拥有者有 读取&#xff0c;写入&#xff0c;执行权限 7 组用户有 读取&#xff0c;写入&#xff0c;执行权限 5 其他用户有 读…

LeetCode 775. 全局倒置与局部倒置

775. 全局倒置与局部倒置 【归并排序】显然全局倒置就是求整体的逆序对&#xff0c;用归并排序的思想可以在O(nlogn)的复杂度下求出逆序对的个数。 class Solution {// 9:56 15int[] nums, tmp;int n;int global(int l, int r) {if (l r) return 0;int m (l r) >> 1;…

Codeforces Round #775 (Div. 2) ABCDE题解

A-Game 题目大意&#xff1a; 一条直线上有若干个点&#xff0c;每个点有两种情况&#xff1a; land 可以经过water 不能经过 每次只能移动一个距离&#xff0c;如果下一个是land&#xff0c;就可以到下一个land上&#xff0c;花费为0。 最多可以使用一次跳跃&#xff0c;从…