其他分享
首页 > 其他分享> > 【UR #6】懒癌

【UR #6】懒癌

作者:互联网

题目无限次看错……当然如果看对了还是做不出。注意一下只会开一枪,然后全局结束。

当然官方题解已经讲的很清楚了,所以还是特别推荐官方题解。


为了更好地理解,先从完全图入手(顺便拿一下部分分)。

假设有 \(K\) 个人,那么没懒狗的会看到 \(K\) 条懒狗,有懒狗的会看到 \(K - 1\) 条。

在第一天,如果没有枪声,说明没有人刚好看到 \(0\) 条,说明大家都至少看到 \(1\) 条。

在第二天,如果有人刚好看到了 \(1\) 条,由于没有 \(0\) 条,则他刚好是最小值 \(K - 1\),说明他有懒狗;如果没有枪声,说明没有人刚好看到 \(1\) 条。

……

归纳可证明所有有懒狗的人都在第 \(K\) 天枪毙懒狗。


再说一般图,相比于完全图,每个人多了一些看不到的狗。

但是,不变的是,每个人都在各自 DP,你预判到了我预判了你的预判,都是在一定的天数积累下得到自己的狗是懒狗。

也就是说,我们要设计一个 dp,得到一个阈值,在这个阈值之后找到懒狗。

那么:

这样,我们枚举懒狗集合,然后根据最后一大条的原则进行转移,得到了一个 \(O(n4^n)\) 的做法。


但是我们在实现的过程中,发现了 DP 有环的情况,但是我们这个时候并不知道转移时是否每一个元素都有用,因此环的作用也不知道。

这个怎么解决呢?

先考虑特殊情况:啥时候会有环。因为看得到的狗是状态不会变的,变的是自己和自己没出边相连的狗。

关于这点,我们很难描述清楚我们的 DP。正难则反,我们交换一下条件,即:

很容易发现,这其实是在反图上操作。

基于这个操作和 DP 的定义,我们很容易给出 DP 有环的另一个定义:在反图上有环。

一个很显然的想法就是环上可以无限操作,但是如果操作环外的点呢?

这说明了如果当前状态环上有懒狗,就整体无解。

同时,缩点成 DAG 后,在图上按拓扑序归纳证明:

这说明了,如果一个懒狗能通过反图有向边到环上,就整体无解。


在反图上,去掉环和能到达环的点,剩下的图是个 DAG。

再梳理一遍我们的改变 DP 状态时的操作:

则我们很容易得到:

如果状态中没懒狗,是终止状态,定义其在第 \(0\) 天会有枪声。加入这个状态完美地契合了我们的转移。

那么显然容易归纳证明,只要存在一条懒狗,就不会在第 \(0\) 天有枪声。

同时因为 DP 的偏序关系,很容易得到,如果对于两个懒狗集合 \(S, T\) 有 \(S \subset T\),则有 \(f(S) \leq f(T)\)。

因为我们在选择懒狗后,改变状态后要使 DP 值最大,那么显然就是全变成懒狗最好了。

于是操作变成:

由于我们是选择所有懒狗的最小时间,那么如果当前状态中,懒狗 \(u\) 能到达懒狗 \(v (v \neq u)\),那么先选择懒狗 \(v\) 是不优的。

于是在每个状态中:

这样,我们得到了一个 \(O(2^n \mathrm{poly}(n))\) 的做法。


当然,都做到这一步了,还能不会多项式做法?

首先取出反图的 DAG,具体可以直接拓扑排序(选出度为 \(0\) 的点)。当然 tarjan 也可以。

即取出来的子图点数为 \(m\)。

考虑到我们可以直接计算单个狗对答案的贡献。

对于第一问,对于一个狗 \(u\),我们得出有多少 \(v\) 能到达 \(u\)(包括 \(u\)),这样:

对于第二问,对于一个狗 \(u\),不能有懒狗 \(v\) 能到达它。

用一个传递闭包,然后直接统计答案即可。

时间复杂度 \(O(\frac{n^3}{\omega})\)。


代码有点赶。

#include <bits/stdc++.h>

const int mod = 998244353;
typedef long long LL;
void reduce(int & x) { x += x >> 31 & mod; }
int mul(int a, int b) { return (LL) a * b % mod; }
int pow(int a, int b, int res = 1) {
	for (; b; b >>= 1, a = mul(a, a)) if (b & 1) res = mul(res, a);
	return res;
}
int remod(LL x) { x %= mod; return x + (x >> 63 & mod); }
const int MAXN = 3010;
typedef std::bitset<MAXN> B;
B to[MAXN];
int n;
int oud[MAXN];
int rk[MAXN], in[MAXN];
int main() {
	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
	std::cin >> n;
	for (int i = 1; i <= n; ++i) {
		static char buf[MAXN];
		std::cin >> buf;
		for (int j = 1; j <= n; ++j)
			if (j != i && buf[j - 1] == '0')
				to[i].set(j), ++oud[i];
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j)
			if (!oud[j]) {
				oud[j] = -1;
				for (int k = 1; k <= n; ++k)
					if (to[k][j])
						--oud[k];
				in[rk[i] = j] = true;
				break;
			}
	}
	int m = std::accumulate(in + 1, in + 1 + n, 0);
	for (int i = 1; i <= m; ++i)
		for (int j = 1; j < i; ++j)
			if (to[rk[i]].test(rk[j]))
				to[rk[i]] |= to[rk[j]];
	int ans1 = 0, ans2 = 0;
	for (int i = 1; i <= m; ++i) {
		int u = rk[i];
		int tc = 1;
		for (int j = i + 1; j <= m; ++j)
			tc += to[rk[j]].test(u);
		reduce(ans1 += mul(pow(2, tc) - 1, pow(2, m - tc)) - mod);
		reduce(ans2 += pow(2, m - tc) - mod);
	}
	std::cout << ans1 << ' ' << ans2 << std::endl;
	return 0;
}

标签:状态,懒狗,环上,int,UR,懒癌,反图,DP
来源: https://www.cnblogs.com/daklqw/p/13669163.html