11.28 模拟赛

总结

T1 读完题就会了。感觉没什么坑直接写。10min 过大样例。没啥好拍的就不拍了。

T2。感觉不难啊,这种模拟 Kruskal 的题都做一堆了。想。

谔谔正解会不了一点。写个乱搞,看看能不能过大样例。

一开始是没过的,因为少写了一种情况。很久之后意识到改过来发现大样例过了!

然后没对拍。当时真不知道在想啥。

T3 什么玩意,样例解释怎么蹦出个 4???对称点是啥?????花了一点时间(<5min)发现题意看不懂一点,而且部分分挺少,不管了看 T4。

然而事实上 T3 的题面确实很脑瘫。赛后听 lhl 才终于理解题意。而且全机房就 lhl 读懂了题。。。。。而且 A 了。。。。。。。Orz Orz Orz

T4。不是有结论”与+或=和“吗。那么问题不久变成了从 [l,r] 内选若干数,使得它们的与和为 sum/2 吗!

想一想做法。nq 暴力平凡。ai15 平凡。随机……或许也是平凡的。有 50!!!!!

赶紧写。

然后样例没过。然后发现自己跟个小丑似的”与+或=和“跟着题一点关系没有。

还是只会 8 分。火大。

T2 做法肯定不是正解,但说不定能骗一堆分。先把保底 50 写了。

然后我还是小丑,ui{0,1} 写了但是忘拼提交的代码上了。

100+40+0+0。T4 咋挂了???哦哦哦哦哦哦出题人题面没写集合不能为空。我***

题解

A. 送信卒

注意到 k 越小最短路一定不会边长。于是二分答案。check 用 Dijkstra。

B. 星际联邦

解法 1(题解做法)

考虑蓝莓(捷克语:Borůvka)算法。


它的思想很类似 Kruskal。Kruskal 一次操作会选择两个连通块合并,而蓝莓算法则是多个。

流程是这样的:

  • 最开始图中有 n 个连通块。即没有边。
  • 为每个点 u 找一条边 (u,v,w),其中 vu 不在同一个连通块内,且 w 最小。将这条边称为这个的 最小边
  • 将所有最小边的端点的两个连通块合并。答案加上这些最小边的边权。
  • 若此时剩余连通块数量 >1,回到第二步。否则结束。

【模板】最小生成树 用蓝莓算法实现如下:

int n, m, p[N];
int best[N];		// 最小边
bool st[N];

struct Edge {
	int a, b, c;
}e[N];

int fifa(int x) {
	return x == p[x] ? x : p[x] = fifa(p[x]);
}

void merge(int a, int b) {
	p[fifa(a)] = fifa(b);
}

bool cmp(int a, int b) {
	if (!b) return true;
	if (e[a].c != e[b].c) return e[a].c < e[b].c;
	return a < b;	// 如果边权相等,视作编号小的边更小。
}

void solve() {
	cin >> n >> m;
	
	for (int i = 1; i <= m; ++ i ) {
		cin >> e[i].a >> e[i].b >> e[i].c;
	}
	
	for (int i = 1; i <= n; ++ i ) {
		p[i] = i;
	}
	
	int cnt = 0, res = 0;
	bool flg = true;
	while (flg) {
		flg = false;
		
		memset(best, 0, sizeof best);	
		for (int i = 1; i <= m; ++ i )
			if (!st[i]) {
				int a = fifa(e[i].a), b = fifa(e[i].b);
				if (a == b) continue;
				if (cmp(i, best[a])) best[a] = i;
				if (cmp(i, best[b])) best[b] = i;
			}
		
		for (int i = 1; i <= n; ++ i )
			if (best[i] && !st[best[i]]) {
				flg = true;
				cnt ++ ;
				res += e[best[i]].c;
				st[best[i]] = true;
				merge(e[best[i]].a, e[best[i]].b);
			}
	}
	
	if (cnt == n - 1) cout << res;
	else cout << "orz";
}

复杂度为什么正确?因为一轮操作后图中连通块的数量至少减半。所以复杂度是 O((n+m)logn)


对于本题,发现一个点 i 的最小边一定是前缀最大值或后缀最小值。直接维护即可。

但是最小边的定义里写明,两个端点不能在同一个连通块内。于是还需要维护前缀次小值和后缀次大值。这里的 表示不和最值连通块相同的最值。

解法 2(乱搞)

考虑对于每个 j,找到所有 i<jai 的前 M 大,和所有 i>jai 的前 M 小。这样边的数量是 O(nM) 的。

实测 M=18 可过。

C. 对称旅行者

考虑期望。

显然一次跳跃后,第 i 个人会从 xi 跳到 12(2xixi1+2xixi+1)=xi1+xi+1xi

然后 P7962 [NOIP2021] 方差。求 x 的差分数组 Δxi=xixi1

那么第 i 个人跳一步,相当于交换 Δxi,Δxi+1

为啥?

原本 Δxi=xixi1。跳跃后 Δxi=xi1+xi+1xixi1=xi+1xi=Δxi+1

原本 Δxi+1=xi+1xi。跳跃后 Δxi+1=xi+1(xi1+xi+1xi)=xi1xi=Δxi

也就是说一轮操作 a1am 相当于依次执行 swap(Δxa1,Δxa1+1)swap(Δxam,Δxam+1)。先暴力做一遍,求出 pi 表示 xi=xpi

然后快速幂维护 pk

最后前缀和。

posted @   2huk  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示