首页 > 其他分享 >CF1795 G.Removal Sequences - 题解

CF1795 G.Removal Sequences - 题解

时间:2023-03-11 12:34:10浏览次数:47  
标签:CF1795 删除 int 题解 Sequences 先于 移除 节点 deg

记 \(N(u)\) 表示图上与点 \(u\) 相邻的点,\(p_u = deg_u - a_u\),其中 \(deg_u\) 为无向图上点 \(u\) 的度数。首先要删除 \(p_u = 0\) 的点,同时 \(\forall v \in N(u), p_v \gets p_v - 1\),归纳地考虑 \(p\) 为 \(0\) 的点即可。由于题目中保证至少存在一个移除序列,所以通过此方式一定可以求得一组合法解。

Additionally: 若给出序列不存在任何合法解,当且仅当在上述算法中,出现了 \(p_u < 0\) 的点或算法结束后仍有未被删除的点。

构造出一组合法解后,考虑该解有何性质。


\(\text{Lemma 1.}\) 对于节点 \(u\),点集 \(N(u)\) 中有且仅有 \(p_u\) 个先于它被删除的节点,且对于所有的合法移除序列,这 \(p_u\) 个节点是相同的(\(\text{i.e.}\) 这 \(p_u\) 个节点总是先于 \(u\) 被移除)。

\(\text{Proof.}\) 由于节点 \(u\) 可被移除当且仅当 \(p_u = 0\),显然我们需要 \(p_u\) 个先于 \(u\) 被删除的节点。假设 \(N(u)\) 中存在一个不属于原先 \(p_u\) 个节点中的节点 \(t\),使得 \(t\) 先于 \(u\) 被移除,这也意味着原先的 \(p_u\) 个节点中出现了一个节点 \(k\) 需要后于 \(u\) 被删除。这样一来,节点 \(k\) 原先需要在点集 \(N(k) \backslash \{ u \}\) 中选 \(p_k\) 个先于 \(k\) 删除的节点,现在只需选择 \(p_k - 1\) 个节点,类似地,剩余那个节点也只需要选择(原先需要的点数 - 1)个节点。这个过程形成了一个归纳,归纳到最后,我们一定会遇到 \(p\) 值为 \(0\) 的节点,这个节点原先需要先于任何与之相邻的节点被删除,然而归纳过程中我们先删除了与其相邻的某个节点,这就导致不合法情况的诞生。因此假设不成立,证毕。


因此,由引理,只需要构造出一组合法解,便可知点对被移除的先后顺序是否固定。我们可以对原图中所有无向边按该解中的先后顺序定向,具体地,对于边 \((u, v)\),若 \(u\) 在序列中先于 \(v\) 出现,则连接一条 \(u \to v\) 的有向边。这样一来,若两点在新图上连通,则其被删除的先后顺序一定是确定的。这样一来就是一个有向图可达点对计数问题了。记可达点对数为 \(num\),则答案为 \(\frac{n(n - 1)}{2} - num\)。

记 \(c_u\) 表示 \(u\) 到 \(n\) 个点是否可达的状态(使用 bitset)。容易发现最终得到的图一定是一个 DAG,建反图后进行拓扑排序,按拓扑序先后考虑,对于节点 \(u\),\(\forall v \in N(u), c_v \gets c_u \text{ or } c_v\) 即可。时间复杂度 \(\mathcal{O} (\frac{n ^ 2}{w})\),空间复杂度 \(\mathcal{O} (\frac{n ^ 2}{w})\),大约 \(\text{1192 MB}\)。分段考虑,每次只考虑每个点点到 \(1000\) 个点是否可达的状态,这样便可以优化空间了。(官方题解还有一种更好的做法,以 64 为段长并使用 unsigned long long 代替 bitset,使用 __builtin_popcountll 函数统计,此时 \(w = 64\),可以大幅降低用时,学到了

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 1e5 + 10, B = 1000;

int deg[N], a[N], p[N], n, m;
vector<int> G[N], G2[N];
vector<int> res;
queue<int> S;
bitset<B> c[N];
void topo1(){
	res.clear();
	for(int i = 1; i <= n; i++)
		if(p[i] == 0) S.push(i);
	while(!S.empty()){
		int u = S.front(); S.pop(); res.push_back(u);
		for(auto &v : G[u])
			if(--p[v] == 0) S.push(v);
	}
}
void topo2(){
	res.clear();
	for(int i = 1; i <= n; i++)
		if(deg[i] == 0) S.push(i);
	while(!S.empty()){
		int u = S.front(); S.pop(); res.push_back(u);
		for(auto &v : G2[u])
			if(--deg[v] == 0) S.push(v);
	}
}
void solve(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
		cin >> a[i], deg[i] = 0, G[i].clear(), G2[i].clear();
	vector<int> u(m), v(m);
	for(int i = 0; i < m; i++){
		cin >> u[i] >> v[i];
		G[u[i]].push_back(v[i]); G[v[i]].push_back(u[i]);
		deg[u[i]]++, deg[v[i]]++;
	}
	for(int i = 1; i <= n; i++)
		p[i] = deg[i] - a[i];
	topo1();
	vector<int> inv(n + 1);
	for(int i = 0; i < n; i++)
		inv[res[i]] = i;
	for(int i = 1; i <= n; i++)
		deg[i] = 0;
	for(int i = 0; i < m; i++){
		if(inv[u[i]] < inv[v[i]])
			G2[v[i]].push_back(u[i]), deg[u[i]]++;
		else G2[u[i]].push_back(v[i]), deg[v[i]]++;
		// 注意 G2 是一个反图
	}
	topo2();
	i64 ans = 1ll * n * (n - 1) / 2;
	for(int i = 1; i <= n; i += B){
		for(int j = 0; j < n; j++){
			int x = res[j];
			if(i <= x && x < i + B) c[x][x - i] = 1, ans++;
			for(auto &y : G2[x])
				c[y] |= c[x];
		}
		for(int j = 1; j <= n; j++)
			ans -= c[j].count(), c[j].reset();
	}
	cout << ans << "\n";
}

标签:CF1795,删除,int,题解,Sequences,先于,移除,节点,deg
From: https://www.cnblogs.com/chroneZ/p/17205650.html

相关文章

  • CF888D Almost Identity Permutations 题解
    CF链接:AlmostIdentityPermutationsLuogu链接:AlmostIdentityPermutations${\scr\color{Aquamarine}{\text{Solution}}}$前言这好像是一道能用数学秒掉的题目但......
  • 「THUPC 2023 初赛」欺诈游戏 题解
    写点无脑做法。设走私者的策略是\(p_i\)概率选\(i\),检查官的策略是\(q_i\)概率选\(i\)。因为两者策略均最优,所以走私者选任意一个数得到的期望收益相同,检查官选任......
  • CF1802D题解
    CF1802D题解传送门更好的阅读体验简化题意:有n个商店,每个商店卖a,b两种商品,价格分别为\(a_i,b_i\),你需要在每个商店买一个商品,并且不能在所有商店都买同一种商品,最......
  • Python - Crypto 导入失败问题解决记录
    python3.7Mac安装psycopg2$pipinstallpsycopg2...Error:pg_configexecutablenotfound....出现报错:Error:pg_configexecutablenotfound.解决参考:h......
  • P5752 [NOI1999] 棋盘分割题解
    本文来自我的洛谷博客。本题解力求使用清晰易懂的图片和文字,讲解最简洁的道理。请大家耐心地看完,注意要结合图片一起哦~~2022-8-24更改了格式与错别字2022-8-28更改......
  • python工具jupyternotebook页面打开空白问题解决方法
    jupyternotebook页面打开空白问题解决方法下载anaconda自带的jupyternotebook找到这个配置文件C:\Users\Administrator.jupyter\jupyter_notebook_config.py打开找......
  • P7712 [Ynoi2077] hlcpq 题解
    虚式优化建图题。首先有一个很显然的暴力,对于两条相交的线段连一条边,然后跑割点。这个暴力的问题在于边与点的时间复杂度相差过大,无论是空间还是时间都无法承受,所以可以......
  • CF1713F 题解
    题意传送门给出一个从\(1\)到\(n\)的数组\(a\),有一个从\(0\)开始标号的大小为\((n+1)\times(n+1)\)的矩阵\(b\),通过以下方式生成:对于\(0\lei\len\),\(b_{i......
  • 江南信息学2023第三周练习20230310 题解
    比赛链接1001:三个数的最大值条件判断,如判断a最大就是a>=b&&a>=c,以此类推1002:星期几取余,n%7结果是0则是周一,是1则周二,以此类推1003:奇偶分家设两个求和变量sum1,sum2......
  • ABC292F题解
    首先先钦定\(a\leb\),否则交换一下就行。方法1:二分答案。容易发现,答案至少为\(a\),并且用左下角为一个顶点一定不会更劣,并且另外两个点一定都在线段上(否则可以调整)。我们......