看板娘加载较慢请耐心等待qwq~~~

2019.10.15模拟赛

关于这次考试

这次考试感觉下发文件高端大气上档次。每个题八个样例,提供详细的数据解析。并且提供了答案文件比较器以及对拍器。真的是很厉害了。虽然T3的std锅了

T1 神在夏至降下了神谕

题面

参与这场演出的一共有 N+M 位战士,其中 N 个人是冬之军,M 个人是夏之军。
冬之军的大将冬男拥有改变季节的力量。他每次可以任意选取恰好 K 名战士,然后把这 K 个人中所有的夏之军变成冬之军,所有的冬之军变成夏之军。
冬男可以使用任意多次改变季节的力量,直到他将所有的人都变成了冬之军。
如果冬男将所有的人都变成了冬之军,那么冬男就获得了胜利。
我想要知道,对于给定的 N,M,K,冬男是否有可能获得胜利。

这题样例太友善了直接告诉答案

分情况讨论一下:
\(m = 0\),直接取得胜利。
\(m\%k =0\),一定可以直接把所有夏之军改为冬之军。
\(m + n {\leq} k\),无法转变夏之军。
\(m 是奇数, k 是偶数\),无论如何转化,都会剩余奇数个夏之军。
\(k是奇数\),无论m奇偶,一定可以修改m个夏之军。
就这样切掉了这道题。

inline bool sov() 
{
    poread(n), poread(m), poread(k);
    if (m % k == 0)
        return 1;
    if (m != 0 && n + m <= k)
        return 0;
    if (m & 1 && !(k & 1))
        return 0;
    return 1;
}

T2 灰狼呼唤着同胞

题面

二十年前的混沌,一共有 n 块碎片。
这 n 块碎片曾经两两之间都有联系,可是很多联系都在时间的洪流中消失了。
现在,我只能确定其中 m 条联系的种类。 每条联系都是一条无向边,任意两块碎片之间至多有一条联系,没有联系会连接在同一块碎片的两端。
联系有两种。一种是冲突,用 0 表示;另一种是吻合,用 1 表示。 虽然已经过去了二十年,但是联系的种类是不会变的。
现在,我想要用这 m 条联系,去推断二十年前的 n(n-1)/2 条联系的种类。
二十年前,对于任意三块互不相同的碎片,要么这三块碎片两两吻合,要么恰好有一对碎 片互相吻合。
我想要知道,二十年前 n 块碎片两两之间的联系,可能有多少种。
你只要输出方案数模 998244353 之后的结果。如果已经确定的 m 条联系不符合上述条件,请输出 0。

咋做

判断是否合法,使用边带权的并查集或者扩展域即可。详见lyd《算法竞赛进阶指南》。
统计方案数:其实就是\(2^{连通块个数 - 1}\)
解释:这道题相当于二分图之间连边计算方案数。
对于每一个联通快,我们都已知其中个点的相互情况。(位于左部节点或者右部节点)。
而它与其他连通块的关系是未定的,我们可以将1号连通块的同一部的节点与二号连通块的某一部节点建立联系,这样的联系会有两种,之后我们则认为1,2两个连通块状态已知。
于是对于每两个连通块,都可以建立这样的联系,一共会有cnt-1个联系,答案就是\(2 ^ {cnt-1}\)
图片解释:

int find(int x)
{
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}
inline void merge(const int &x, const int &y)
{
	register int X = find(x), Y = find(y);
	if (X != Y)
		fa[Y] = X;
}
inline int sov()
{
	poread(n), poread(m);
	cerr << n << m << endl;
	for (register int i = 1; i <= n * 2; ++i)
		fa[i] = i;
	for (register int i = 1, x, y, t; i <= m; ++i)
	{
		poread(x), poread(y), poread(t);
		if (t == 1)
		{
			if (find(x + n) == find(y) || find(y + n) == find(x))
			{
				for(;i < m; ++i)
					poread(x),poread(y),poread(t);
				return 0;
			}
			merge(x, y);
			merge(x + n, y + n);
		}
		else
		{
			if (find(x) == find(y) || find(x + n) == find(y + n))
			{
				for (; i < m; ++i)
					poread(x), poread(y), poread(t);
				return 0;
			}
			merge(x, y + n);
			merge(x + n, y);
		}
	}
	register int cnt = 0;
	for (register int i = 1; i <= n; ++i)
		cnt += (fa[i] == i);
	cerr << cnt << endl;
	return qpow(2, cnt - 1);
}

T3 两只怪物心心相印

ps:这题竟然线段树优化建图,考场上见了就暴力分走人了。还有,std竟然锅了。

题面

【题目背景】 从前我是一位无名的旅人,旅途中我得到了某样东西:贤者之石。我因此得到悠久的时光 和漂泊的生命。1897 年冬天,我一时兴起舍弃了旅人的生活。 贤者之石创造出来的,是货真价实的黄金。我的名声传遍了整个国家。
【题目描述】 炼金术的要素,是炼金树和贤者之石。
炼金树是一棵含有 n 个节点的无根树,树上一共有 n-1 条石榴色的无向边。第 i 条无向边 长度为 Li。
我一共会使用 m 次炼金术。
每次使用炼金术时,我首先会把一块石榴色的贤者之石放在炼金树的某个节点 x1 上。然后, 我会将若干块蓝色的贤者之石放在炼金树的其它 K1 个节点上。保证一个节点不会同时放入两块 贤者之石。然后,我会使石榴色的贤者之石熔化。熔化后的贤者之石,只能沿着石榴色的边流 动,既不会与蓝色的贤者之石接触,也不会进入蓝色的贤者之石所处的节点内。凝固后,含有 石榴色的贤者之石的节点集合记为 S1。很显然,S1 是一个包含 x1 的连通块。记 S1 的大小为 |S1|。
题目截图
对于上图所示的炼金树,如果我把石榴色的贤者之石放在 5 号节点,把 4 块蓝色的贤者之 石分别放在 1、3、7、9 号节点,那么熔化后石榴色的贤者之石就会流到 2、5、6、8 号节点。 此时 S1={2,5,6,8},|S1|=4。
然后,取出所有的贤者之石,选择 x2、K2 和新的 K2 个节点,用相同的方法,可以再次确 定一个节点集合 S2。记 S2 的大小为|S2|。你可以认为,确定 S1 的过程和确定 S2 的过程是互 不干扰的。
最后,从 S1 中的每个节点分别向 S2 中的每个节点连一条长度为 W 的金色的有向边。注意, 在同一次炼金术中连接的金色边长度都相同。
很显然,每次使用炼金术,都会增加|S1|*|S2|条有向边。
由于贤者之石熔化后只能沿石榴色的边流动,因此每次炼金术是相互独立的。 有时 S1 里面只会包含 1 个节点 x,那么我可以不需要使用蓝色的贤者之石,直接将石榴色 的贤者之石放在 x 号节点即可确定 S1,此时令 K1=-1。当然,我也可以用上述方法确定 S2, 此时令 K2=-1。
使用完 m 次炼金术后,我会在 1 号节点灌入液态的黄金。黄金既可以沿石榴色的边流动, 也可以沿金色的有向边流动。很显然,黄金流入 i 号节点的时间,就是 1 号节点到 i 号节点的 最短路。
我想要知道,使用完 m 次炼金术后,黄金从 1 号节点流入每个节点的时间。
简单来说,在一棵树上,每次由一部分点向另一部分点连接有向边,求最后根节点到所有节点的最短路长度

考场骗得76分

由于每次更新是由S1更新S2,类似SPFA的做法,挑选出S1中d[x]最小的点x_s1,并由x_s1更新S2中所有点的d[x]。更新之后,由于S2的更改会导致全图中的最短路更新,所以再跑一遍SPFA。时间复杂度\(O(nm)\),于是乎76分骗到手。

但是

这个算法是错误的
在由x_s1更新d[x]后,并没有更新边权,于是乎下次更新x_s1之后,会按照更劣的边长更新d[x]以及全图最短路,导致答案错误。
详情看图:

不要说直接修改边权,因为如果在树上会有很多边根本没有建出来同样没有更新。
数据太水过了不少分。。。

正解

线段树优化建图。
先咕咕咕,学会了再来更新。

posted @ 2019-10-16 14:06  椎名·六花  阅读(131)  评论(1编辑  收藏  举报