8.18 模拟赛小记

发布时间 2023-08-20 15:37:29作者: Moyyer_suiy

A.加速器 洛谷原题指路:P4822 [BJWC2012] 冻结

就是一个分层图的板子。建 k 层图,然后相邻的两层相连时边权除以二即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, k;
int vis[N], ans[N];
int idx, head[N], w[N], nxt[N], e[N];
struct node{
	int u, dis;
	bool operator <(const node& x) const{
		return x.dis < dis;
	} 
};
void add(int x, int y, int z)
{
	e[++ idx] = y;
	w[idx] = z;
	nxt[idx] = head[x];
	head[x] = idx;
}
void dij()
{
	priority_queue<node> q;
	q.push((node){1, 0});
	while(q.size())
	{
		int x = q.top().u;
		q.pop();
		vis[x] = 1;
		for(int i = head[x]; i; i = nxt[i])
		{
			if(! vis[e[i]] && ans[e[i]] > ans[x] + w[i])
			{
				ans[e[i]] = ans[x] + w[i];
				q.push((node){e[i], ans[e[i]]});
			}
		}
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	while(m -- )
	{
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		for(int j = 0; j <= k; j ++ ) add(j * n + x, j * n + y, z), add(j * n + y, j * n + x, z);
		for(int j = 0; j < k; j ++ ) add(j * n + x, (j + 1) * n + y, z / 2), add(j * n + y, (j + 1) * n + x, z / 2);
	}
	for(int i = 1; i <= n * k + n; i ++ ) ans[i] = 0x7fffffff;
	ans[1] = 0;
	dij();
	int minn = 0x7fffffff;
	for(int i = 0; i <= k; i ++ ) minn = min(minn, ans[i * n + n]);
	printf("%d", minn);
	return 0;
}

B.没有矛盾的舞会 洛谷原题指路:P2607 [ZJOI2008] 骑士

只要你会 P1352 没有上司的舞会 就发现是一样的套路,唯一的区别是 P1352 有 n 个点 n - 1 条边,是一棵树,而本题有 n 个点,必然存在一条边。这就是基环树了(去掉基环树里的环,它就是一颗普通的树)。

基环树是图不是树。

那我们要做的就是破环为链,然后将得到的两个链跑 dp 求一个 max,其余思路与 P1352 相同。


C.奶牛串门 洛谷原题指路:P3469 [POI2008] BLO-Blockade

需要讨论这个点是否是割点,用 tarjan 缩点同时记录连通块大小,利用乘法原理统计。


D.过路费 洛谷原题指路:P2245 星际导航

需要最小生成树。

一种做法是 kruskal + lca。

另一种老师刚讲的 kruskal 同构树,你会发现神奇的性质,然后就能做了。