首页 > 其他分享 >2023/11/15 NOIP 模拟赛

2023/11/15 NOIP 模拟赛

时间:2023-11-15 18:35:23浏览次数:46  
标签:11 return NOIP int ll mid void 15 mx

T1 游戏

标签

尺取 线段树 单调队列
线段树进阶

思路

抽象题意,相当于有 \(t\) 个点,有 \(n\) 个下接 \(x\) 轴的矩形。

首先明显可以按照 \(c\) 排序,然后尺取。

写法

线段树记录每区间内未被覆盖的最大高度。

因为插入和删除的顺序相对不变,一个单调队列维护该区间内矩形高度即可,若有删除操作则向儿子取 \(\max\) 重新计算 \(mx\)

代码

常数极大,可使用内存池优化。

code
ci N = 1e6 + 9;
ci inf = 2e9;

int t, n, ans(inf);
int a[N], b[N], c[N], v[N], h[N], id[N];

bool cmp(int x, int y) {return c[x] < c[y];}

struct SGT {
	#define lc ((u) << 1)
	#define rc ((u) << 1 | 1)
	int mx[N << 2], buf[N * 40];
	unsigned int head[N << 2], tail[N << 2];
	il void pushup_mx(int u) {
		if(head[u] > tail[u]) return;
		if(v[q[u][head[u]]] >= mx[u]) mx[u] = 0;
	}
	il void pushup(int u) {
		mx[u] = max(mx[lc], mx[rc]);
		pushup_mx(u);
	}
	il void build(int u, int l, int r) {
		if(l == r) return mx[u] = h[l], void();
		int mid = (l + r) >> 1;
		build(lc, l, mid);
		build(rc, mid + 1, r);
		pushup(u);
	}
	il void insert(int u, int l, int r, int a, int b, int i) {
		if(a <= l && r <= b) {
			while(head[u] < q[u].size() && v[*(-- q[u].end())] <= v[i]) q[u].pop_back();
			q[u].eb(i);
			if(v[q[u][head[u]]] >= mx[u]) mx[u] = 0;
			return;
		}
		if(b < l || r < a) return;
		int mid = (l + r) >> 1;
		insert(lc, l, mid, a, b, i);
		insert(rc, mid + 1, r, a, b, i);
		pushup(u);
	}
	il void erase(int u, int l, int r, int a, int b, int i) {
		if(a <= l && r <= b) {
			if(q[u][head[u]] == i) {
				++ head[u];
				if(l == r) {
					mx[u] = h[l];
					pushup_mx(u);
				}
				else {
					pushup(u);
				}
			}
			return;
		}
		if(b < l || r < a) return;
		int mid = (l + r) >> 1;
		erase(lc, l, mid, a, b, i);
		erase(rc, mid + 1, r, a, b, i);
		pushup(u);
	}
} tree;

il void ins(int i) {
	tree.insert(1, 1, t, a[i], b[i], i);
}

il void ers(int i) {
	tree.erase(1, 1, t, a[i], b[i], i);
}

int main() {
	freopen("game.in", "r", stdin);
	freopen("game.out", "w", stdout);
	rd(t); rd(n);
	rep(i, 1, n) {
		rd(a[i], b[i], c[i], v[i]);
		id[i] = i;
	}
	sort(id + 1, id + n + 1, cmp);
	rep(i, 1, t) rd(h[i]);
	tree.build(1, 1, t);
	int L = 1;
	rep(_i, 1, n) {
		int i = id[_i];
		ins(i);
		while(tree.mx[1] == 0) {
			cmin(ans, c[i] - c[id[L]]);
			ers(id[L]); ++ L;
		}
	}
	pt("%d\n", ans);
	return 0;
}

T2 驻军

标签

长链剖分,树上前缀和进阶

思路

订正的时候没有对答案取模再乘,dfs 时没有判长链。

考虑将找链转化为对端点处理,发现可以通过处理将答案变为只与 \(lca(x, y), x, y\) 有关的形式,这样才能进行长链剖分。

约定

\(f_u\) 表示 \(u\) 子树所有点到 \(u\) 的距离和。

\(e_{u, v}\) 表示 \((u\to v)\) 的边权。

\(h_u\) 表示 \(u\) 子树所有点到 \(u\) 的距离和。

\(sz_u\) 表示 \(u\) 子树的大小。

\(w_v\) 表示 \((fa_v\to v)\) 的贡献,等于 \(sz_v\cdot e_{fa_v, v}\)。

\(s_u\) 表示从 \(u\) 到根(可设为 \(1\))的简单路径上的边的 \(w\) 之和,等于 \(w_u + w_{fa_u} + \cdots\)

转移

若路径为 \(x, y\),设 \(lca(x, y) = u\) 则答案为 \(h_u + f_u - (s_x - s_u) - (s_y - s_u)\)。

这个比较难,可对每条边快速统计多算的贡献,减去即可。

\(f_u = \sum\limits_{u\to v} (f_v + w_v)\)

\(s_v = s_u + w_v\)

\(h_v = (n - sz_v)\cdot e_{u, v} + h_u + f_u - f_v - w_v\)

代码

code
ci N = 2e6 + 9;
const ll INF = 1e18;

int n, k;

ll sz[N], f[N], s[N], h[N], w[N];

vector<pii> A[N];

void dfs1(int u, int la) {
	sz[u] = 1;
	for(pii e : A[u]) {
		int v = e.fi;
		if(v == la) continue;
		dfs1(v, u);
		sz[u] += sz[v];
		w[v] = sz[v] * e.se;
		f[u] += f[v] + w[v];
	}
}

int depth[N], son[N];
void dfs2(int u, int la) {
	depth[u] = 1;
	for(pii e : A[u]) {
		int v = e.fi;
		if(v == la) continue;
		s[v] = s[u] + w[v];
		h[v] = 1LL * (n - sz[v]) * e.se + h[u] + (f[u] - f[v] - w[v]);
		dfs2(v, u);
		cmax(depth[u], depth[v] + 1);
		if(depth[v] + 1 == depth[u]) son[u] = v;
	}
}

ll buc[N], *mx[N], ans(INF);

void dfs(int u, int la) {
	mx[u][1] = s[u];
	if(son[u]) {
		mx[son[u]] = mx[u] + 1;
		dfs(son[u], u);
		for(pii e : A[u]) {
			int v = e.fi;
			if(v == la || v == son[u]) continue;
			mx[v] = mx[u] + depth[u];
			dfs(v, u);
			rep(i, 1, depth[v]) {
				if(i > 0 && k - i > 1 && i <= depth[v] && k - i <= depth[u]) {
					cmin(ans, h[u] + f[u] + 2 * s[u] - mx[u][k - i] - mx[v][i]);
					if(ans < 0) {
						printf("%lld %lld %lld\n", h[u], f[u], s[u]);
						printf("u-road = %d v = %d\n", u, v), exit(0);
					}
				}
			}
			rep(i, 1, depth[v]) cmax(mx[u][i + 1], mx[v][i]), mx[v][i] = 0;
		}
	}
	if(depth[u] >= k) {
		cmin(ans, h[u] + f[u] + s[u] - mx[u][k]);
		if(ans < 0) printf("u-list = %d\n", u),exit(0);
	}
}

ci mod = 998244353;

ll fpow(ll a, ll x) {
	ll res = 1;
	while(x) {
		if(x & 1) res = res * a % mod;
		a = a * a % mod;
		x >>= 1;
	}
	return res;
}

int dis[N];
void _dfs(int u, int la) {
	dis[u] = dis[la] + 1;
	for(pii e : A[u]) {
		if(e.fi == la) continue;
		_dfs(e.fi, u);
	}
}

int main() {
    // freopen("barrack.in", "r", stdin);
    // freopen("barrack.out", "w", stdout);
    freopen("a.in", "r", stdin);
	rd(n, k);
	rep(i, 2, n) {
		int x, y, z;
		rd(x, y, z);
		A[x].eb(mp(y, z));
		A[y].eb(mp(x, z));
	}

	int st = 1;
	_dfs(1, 0);
	rep(i, 2, n) {
		if(dis[i] > dis[st]) {
			st = i;
		}
	}
	_dfs(st, 0);
	rep(i, 1, n) {
		if(dis[i] > dis[st]) {
			st = i;
		}
	}
	if(dis[st] < k) return puts("-1"), 0;

	dfs1(1, 0);
	dfs2(1, 0);
	mx[1] = buc;
	dfs(1, 0);
	printf("%lld\n", ans % mod * fpow(n, mod - 2) % mod);
	return 0;
}

T3 序列

标签

离线
线段树入门

思路

考虑将所有操作离线,对于每一个位置 \(i\) 处理询问

第 \(j\) 次询问 \(p,k\) 相当于将 \(0\to k - 1\) 的前缀和与 \(k\sim j\) 的 \(\gcd\) 求一个 \(\gcd\),开个线段树维护一下区间和和区间 \(\gcd\) 即可。

感觉比 T2 简单。

代码

代码好写。

code
ci N = 2.5e5 + 9;

int n, q;
int a0[N], qval[N], op[N];
ll ans[N];
vector<int> ins[N], ers[N];
vector<int> qry[N];

ll gcd(ll a, ll b) {return !b ? a : gcd(b, a % b);}

struct SGT {
	#define lc ((u) << 1)
	#define rc ((u) << 1 | 1)
	int tr_gcd[N << 2];
	ll tr_sum[N << 2];
	void push_up(int u) {
		tr_sum[u] = tr_sum[lc] + tr_sum[rc];
		tr_gcd[u] = gcd(tr_gcd[lc], tr_gcd[rc]);
	}
	void modify(int u, int l, int r, int loc, int var) {
		if(l == r) {
			tr_gcd[u] = tr_sum[u] = var;
			return;
		}
		int mid = (l + r) >> 1;
		if(loc <= mid) modify(lc, l, mid, loc, var);
		else modify(rc, mid + 1, r, loc, var);
		push_up(u);
	}
	ll querysum(int u, int l, int r, int a, int b) {
		if(a <= l && r <= b) return tr_sum[u];
		if(b < l || r < a) return 0;
		int mid = (l + r) >> 1;
		return querysum(lc, l, mid, a, b) + querysum(rc, mid + 1, r, a, b);
	}
	int querygcd(int u, int l, int r, int a, int b) {
		if(a <= l && r <= b) return tr_gcd[u];
		if(b < l || r < a) return 0;
		int mid = (l + r) >> 1;
		return gcd(querygcd(lc, l, mid, a, b), querygcd(rc, mid + 1, r, a, b));
	}
} tree;

int main() {
	freopen("sequence.in", "r", stdin);
	freopen("sequence.out", "w", stdout);
	rd(n, q);
	rep(i, 1, n) rd(a0[i]);
	rep(i, 1, q) {
		rd(op[i]);
		if(op[i] == 1) {
			int l, r; rd(l, r, qval[i]);
			ins[l].eb(i);
			ers[r + 1].eb(i);
		}
		else {
			int p; rd(p, qval[i]);
			qry[p].eb(i);
		}
	}
	rep(i, 1, n) {
		for(int j : ins[i]) {
			tree.modify(1, 1, q, j, qval[j]);
		}
		for(int j : ers[i]) {
			tree.modify(1, 1, q, j, 0);
		}
		for(int j : qry[i]) {
			ans[j] = gcd(a0[i] + tree.querysum(1, 1, q, 1, qval[j] - 1), tree.querygcd(1, 1, q, qval[j], j));
		}
	}
	rep(i, 1, q) {
		if(op[i] == 2) {
			printf("%lld\n", abs(ans[i]));
		}
	}
	return 0;
}

标签:11,return,NOIP,int,ll,mid,void,15,mx
From: https://www.cnblogs.com/SkyMaths/p/17833575.html

相关文章

  • 第11周课堂内容
    6.1I/O重定向大多数进程都有0.1.2这3个文件描述符。0表示标准输入,可以理解为键盘输入。1表示标准输出,输出到终端。2表示标准错误,输出到终端。3及以上为常规文件的描述符。date命令在默认情况下将输出结果显示在终端,此时文件描述符为1.现在改变输出的方向,从终端改为date.txt文件......
  • 2023.11.15日报
    今天下午去听了九天杯的讲座,说实话,如果是类似pat那种提交做题形式的比赛还有点兴趣参加一下毕竟不至于是提交一个大的作品然后评分(笑),然后就是继续在做大数据的实验,spark的内容已经进行完毕了,主要是安装了一个scala,scala类似maven,只不过在打包之前需要写一个scala和spark的版本......
  • 11月14日函数的定义
    目录函数的定义1.普通函数定义2.带参数的函数3.带返回值的函数4.匿名函数方式5.箭头函数6.函数体内用arguments关键字接收所有的参数函数的定义1.普通函数定义基本格式functionfunctionName(parameters){//函数体//可以包含多条语句;}例子如下functionfun(......
  • 【做题笔记】NOIP真题们
    [NOIP2022]种花题意不太好描述,感性理解(题意一道计数类问题。不难发现F形只需要在C形的基础上在末尾伸出一小支就好了。所以我们先考虑C形的计数方案。图形计数类一个基本的trick就是枚举拐点,因此我们考虑枚举下面这一行的拐点(也就是首个种花的位置)\((i,j)\)。令上面......
  • 2023NOIP A层联测31 T4 民主投票
    2023NOIPA层联测31T4民主投票思维好题。思路首先可以设\(s\)每个人最多获得的票数,一开始所有点都把自己的票投给自己父亲。如果一个点的票数超过\(s\)了,那么这个点肯定要把票分给他的父亲。设\(f_{u,s}\)为\(u\)点在最多获得\(s\)票的情况下要向父亲分的票数(不......
  • 超音速亚原子 Java 框架来了,0.0015 秒内启动一个应用,太快了。。
    来源:juejin.cn/post/70233173515630018861、概述SpringBoot框架不用多介绍,Java程序员想必都知道。相对来说熟悉Quarkus的人可能会少一些。Quarkus首页放出的标语:超音速亚原子的Java(SupersonicSubatomicJava)。它是为OpenJDKHotSpot和GraalVM量身定制的KubernetesNative......
  • 这个红头文件做了15遍!!!
    今天是2020-02-1720:57,真的很佩服自己的耐心!一朋友说自己需要调整一张图片的几个字,于是花了许久才昨晚,或许是能力有限吧,后面仔细一看,做了15遍,仔细想想,还有一层原因就是,我那朋友的要求的确比较高。今天小编给大家分享一下,ps学习过程中的一些心得吧!当涉及到学习使用PS(Photoshop)这款......
  • 20231109 我如何看待命题:计算机不能解决那些计算机外部世界无解决方法的问题
    “解释为什么计算机不能解决那些计算机外部世界无解决方法的问题”是《计算机科学导论》第一章的第一道课后习题,以下是我的回答:在2023年的今天,我并不完全认同这个问题预设的命题,即“计算机不能解决那些计算机外部世界无解决方法的问题”(以下简称“命题A”)。1、什么是“计算机”......
  • 【转】JDK8 升级 JDK11 最全实践干货来了 | 京东云技术团队
    原文地址:JDK8升级JDK11最全实践干货来了|京东云技术团队作者:京东云开发者1.前言截至目前(2023年),Java8发布至今已有9年,2018年9月25日,Oracle发布了Java11,这是Java8之后的首个LTS版本。那么从JDK8到JDK11,到底带来了哪些特性呢?值得我们升级吗?而且升级过程会......
  • 2023/11/5关于如何治疗胃病
    关于冬天喝冷水这件事情。前年死的最惨,各种乱七八糟的操作,最有效的还是床上躺,治好了。去年纯属搞笑,早上喝了一瓶冰牛奶就算了,在hf上竞赛没有好好吃饭,原因是不想排队,不想选吃什么,然后直接被遣送回家,好好吃了一顿饭以后就神奇恢复了。昨天,继续作死了深夜搁那里没事喝冷饮料干什......