首页 > 其他分享 >LY1154 [ 20230320 CQYC省选模拟赛 T1 ] 选拔士兵

LY1154 [ 20230320 CQYC省选模拟赛 T1 ] 选拔士兵

时间:2024-03-06 15:47:35浏览次数:28  
标签:LY1154 20230320 省选 tag mid int stk2 edge tp2

题意

P 和 T 各有 \(n\) 个课程。

P 的课程类型由 \(a_i\) 表示,价值为 \(x_i\) 。

T 的课程类型由 \(b_i\) 表示,价值为 \(y_i\)。

同样的课程不能上两遍。

需要满足 P 和 T 的课程各在同一区间内。

不选输出 \([0, 0]\),问使得价值最大的方案。

Sol

非常好数据结构题,使我的大脑旋转。

考虑简化问题。

注意到一个显然的方案,只上 P 或者 T 就能使得价值超过总价值的一半。

trivial 地,考虑假设 P 的价值超过一半,那么我们不难发现,P 中一定有一点 \(p'\) 必选。

为什么呢?考虑一个前缀和,那么对于 \(p'\) 来说,\([1, p']\) 超过 P 中价值的一半。\([p', n]\) 超过 P 中价值的一半。

而最优答案应该类似于在 T 中选取一段区间,刚好卡住最大的 P 的区间。

因此 \(p'\) 点必选。

如果注意力集中到这里,就非常好做了。

枚举 T 的右端点,用线段树维护 P 的价值。

发现这里要用两个单调栈维护 P 的左右端点。

时间复杂度 \(O(n \log n)\)

细节很多。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <cassert>
#define int long long
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
	int p = 0, flg = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') flg = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		p = p * 10 + c - '0';
		c = getchar();
	}
	return p * flg;
}
void write(int x) {
	if (x < 0) {
		x = -x;
		putchar('-');
	}
	if (x > 9) {
		write(x / 10);
	}
	putchar(x % 10 + '0');
}
bool _stmer;

const int N = 1e6 + 5;

array <int, N> sum1, sum2;
array <int, N> s1, s2;

int _sum;

namespace Sgt {

array <int, N * 4> edge, tag;

void pushup(int x) { edge[x] = max(edge[x * 2], edge[x * 2 + 1]); }

void pushdown(int x) {
	if (!tag[x]) return;
	edge[x * 2] += tag[x];
	edge[x * 2 + 1] += tag[x];
	tag[x * 2] += tag[x];
	tag[x * 2 + 1] += tag[x];
	tag[x] = 0;
}

void build(int x, int l, int r) {
	if (l == r) {
		edge[x] = _sum - sum2[l - 1];
		return;
	}
	int mid = (l + r) >> 1;
	build(x * 2, l, mid);
	build(x * 2 + 1, mid + 1, r);
	pushup(x);
}

void modify(int x, int l, int r, int L, int R, int y) {
	if (L > r || R < l) return;
	if (L <= l && R >= r) {
		edge[x] += y;
		tag[x] += y;
		return;
	}
	pushdown(x);
	int mid = (l + r) >> 1;
	if (L <= mid) modify(x * 2, l, mid, L, R, y);
	if (R > mid) modify(x * 2 + 1, mid + 1, r, L, R, y);
	pushup(x);
}

int query(int x, int l, int r) {
	if (l == r) return l;
	pushdown(x);
	int mid = (l + r) >> 1;
	if (edge[x * 2] > edge[x * 2 + 1]) return query(x * 2, l, mid);
	else return query(x * 2 + 1, mid + 1, r);
}

}

array <int, N> stk1, stk2;
array <int, N> idx;
int lp1, rp1, lp2, rp2;
int ans;

void solve(int n, int m, bool flg) {
	Sgt::edge.fill(0);
	Sgt::tag.fill(0);
	idx.fill(0);
	int pos = 0;
	_sum = sum1[n];
	for (int i = 1, flg = 0; i <= n && !flg; i++)
		if (sum1[i] >= (sum1[n] + 1) / 2)
			pos = i, flg = 1;
	assert(pos);
	Sgt::build(1, 1, m);
	for (int i = 1; i <= n; i++) idx[s1[i]] = i;
	int _lp1 = 1, _rp1 = n, _lp2 = 0, _rp2 = 0;
	int ans = sum1[n];
	int tp1 = 0, tp2 = 0;
	for (int i = 1; i <= m; i++) {
		if (idx[s2[i]] < pos) {
			if (idx[s2[i]]) {
				while (tp1 && idx[s2[stk1[tp1]]] < idx[s2[i]])
					Sgt::modify(1, 1, m, stk1[tp1 - 1] + 1, stk1[tp1], sum1[idx[s2[stk1[tp1]]]]), tp1--;
				Sgt::modify(1, 1, m, stk1[tp1] + 1, i, -sum1[idx[s2[i]]]);
				tp1++;
				stk1[tp1] = i;
			}
		}
		else {
			while (tp2 && idx[s2[stk2[tp2]]] > idx[s2[i]])
				Sgt::modify(1, 1, m, stk2[tp2 - 1] + 1, stk2[tp2], sum1[n] - sum1[idx[s2[stk2[tp2]]] - 1]), tp2--;
			Sgt::modify(1, 1, m, stk2[tp2] + 1, i, sum1[idx[s2[i]] - 1] - sum1[n]);
			tp2++;
			stk2[tp2] = i;
		}
		int tp = Sgt::query(1, 1, m), ls, rs;
		ls = lower_bound(stk1.begin() + 1, stk1.begin() + 1 + tp1, tp) - stk1.begin();
		if (ls > tp1) ls = 1;
		else ls = idx[s2[stk1[ls]]] + 1;
		rs = lower_bound(stk2.begin() + 1, stk2.begin() + 1 + tp2, tp) - stk2.begin();
		if (rs > tp2) rs = n;
		else rs = idx[s2[stk2[rs]]] - 1;
		int sum = Sgt::edge[1] + sum2[i];
		if (sum > ans) {
			ans = sum;
			_lp1 = ls, _rp1 = rs;
			_lp2 = tp, _rp2 = i;
		}
	}
	if (flg) swap(_lp1, _lp2), swap(_rp1, _rp2);
	if (_lp1 > _rp1) _lp1 = _rp1 = 0;
	if (_lp2 > _rp2) _lp2 = _rp2 = 0;
	if (ans > ::ans) ::ans = ans, lp1 = _lp1, rp1 = _rp1, lp2 = _lp2, rp2 = _rp2;
}

bool _edmer;
signed main() {
	cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
#ifndef cxqghzj
	freopen("soldier.in", "r", stdin);
	freopen("soldier.out", "w", stdout);
#endif
	int n = read(), m = read();
	for (int i = 1; i <= n; i++) s1[i] = read();
	for (int i = 1; i <= n; i++) sum1[i] = read() + sum1[i - 1];
	for (int i = 1; i <= m; i++) s2[i] = read();
	for (int i = 1; i <= m; i++) sum2[i] = read() + sum2[i - 1];
	bool flg = 0;
	solve(n, m, flg);
	flg = 1, swap(n, m), swap(sum1, sum2), swap(s1, s2);
	solve(n, m, flg);
	/* write(pos), puts(""); */
	/* if (ans == 117256687380782) { */
		/* puts("78473183868459"); */
		/* puts("1 318759"); */
		/* puts("153463 153502"); */
		/* return 0; */
	/* } */

	write(ans), puts("");
	write(lp1), putchar(32), write(rp1), puts("");
	write(lp2), putchar(32), write(rp2), puts("");
	return 0;
}

标签:LY1154,20230320,省选,tag,mid,int,stk2,edge,tp2
From: https://www.cnblogs.com/cxqghzj/p/18056754

相关文章

  • 联合省选 2024 游记
    来不及踩剎车就匆匆来到这一路上的曲折翻页也忘了不晓得这身躯壳还能走多远呢如果我只剩今夜我能留下什么前言考前一直在复习模板和以前的做题笔记,中间试机的时候还反向挂分AK了一场模拟赛,消耗rp,rp--。考前的晚上有点紧张,和父母聊了聊,他们说无论如何你这个水平的都......
  • LY1162 [ 20230323 CQYC省选模拟赛 T3 ] 跳!跳!跳!
    题意给定\(n\)个长度为\(m\)的字符串,进行若干操作,求每个字符串\(S_a\)到\(S_b\)的方案数。另外,你还有一个模式串\(T\),由\({1,...,n}\)与\(0\)(通配符)组成。从\(S_x\)右边的串开始,不断向右移动,直到\(S_y\)与\(T\)匹配。从\(S_x\)左边的串开始,不断向左......
  • 联合省选 2024 游记
    Day0酒店很好,午餐和晚餐都很好。试机,发现不会配置sublime,因为不会配置g++。晚上奔波1km去吃M记。Day1配置sublime长达7min。先看T1,大概花了40min,想出做法,具体是对每天独立分析,一次函数拆绝对值后二分零点。写完大概1.5h,去看T2,先打了暴力12pts.看T3,指数塔......
  • 联合省选 2024 游记
    Day0考前一天本来放假的,但是父母报了来校自习,被迫来到学校,但是机房又被占了,跑到二楼古董机房自习,体会了一下\(\times6\)常数的缓慢感。自习的时候一直在看数据结构、多项式和数学之类的东西,然后省选一个没考。Day1早上起来,感到了已经很久没有过了的睡饱了的十分清醒的感觉......
  • 联合省选2024游记
    day-???THUWC和NOIWC都结束了,一个2=一个Cu,太失败了。面基了HE的其他几个oier,大家都好厉害。回家摆烂,跟上了NFLS的模拟赛,天天被吊打/jk在省选前三周下载米哈游最新力作崩坏星穹铁道然后愤怒开玩,两周过完了主线返校了。day-2教练问高一选手有没有想去体验一下省选的,竟然还可......
  • 题解 P10220【[省选联考 2024] 迷宫守卫】
    \(\text{Link}\)葬送了我2024省选的一题。题意有一颗深度为\(n+1\)的完全二叉树,其叶子上依次标有一个长为\(2^n\)排列\(a\),非叶结点有选择代价\(b_i\)。Alice、Bob两人进行游戏。Alice可以选择一些选择代价和不超过\(m\)的非叶结点,此后Bob会从根开始深度优先搜索......
  • 2023 NOIP + 2024 陕西省选 游记
    前言:陕西省选\(1\)月就考完了,而联合省选要等到\(3\)月。现在写这篇文章的时间正好是\(2024.3.5\),联合省选结束后第一天。2023.11.1xmd怎么还不让我去体验NOIP,是不是看不起人。几天后:好的CCF最牛逼。2023.11.18考NOIP力。人员变化不大,基本上都来了。又是周六,继......
  • 联合省选 2024 游记
    Day-2打了一场CFdiv.2,很平常地切了4题结果一看排行居然排到了26名?省选信心赛!第二天上紫名了,洛谷个签可以改了()Day0上午狠狠地学习了线段树优化建图,过了板子题。然后还想复习一下整体二分,于是找到了P4602[CTSC2018]混合果汁打算写一下。然而下午直接pvz启动,什......
  • [省选联考 2024] 题解
    D1T1P10217季风题意有点抽象,大概就是要求我们对两个有若干次重复的序列进行操作,每次可以将这两个序列都向上或向下调整一个值,但是调整的绝对值的总和有限制,问能否最终将总和调整至固定值。由于\(m\)不一定是\(n\)的倍数,因此序列在重复若干次之后可能会遗留一些散块,这是不......
  • P10217 [省选联考 2024] 季风 题解
    [省选联考2024]季风Description给定\(n,k,x,y\)和\(2n\)个整数\(x_0,y_0,x_1,y_1,\dots,x_{n-1},y_{n-1}\)。找到最小的非负整数\(m\),使得存在\(2m\)个实数\(x_0',y_0',x_1',y_1',\dots,x_{m-1}',y_{m-1}'\)满足以下条件,或报告不存在这样的\(m\):\(\s......