首页 > 其他分享 >AtCoder Regular Contest 144 E GCD of Path Weights

AtCoder Regular Contest 144 E GCD of Path Weights

时间:2023-11-22 18:45:45浏览次数:36  
标签:AtCoder 144 GCD int 边权 typedef long maxn ans

洛谷传送门

AtCoder 传送门

喵喵题。

考虑若所有点权都已确定,如何求 \(1\) 到 \(n\) 所有路径权值和的 \(\gcd\)。

考虑如何 check 一个 \(x\) 是否合法。\(x\) 合法的充要条件是,把不能从 \(1\) 到达的点和不能到达 \(n\) 的点扔掉后,存在一组 \(\{f_n\}\),使得对于每条 \(u \to v\),边权为 \(d\) 的边,都满足 \(f_v - f_u \equiv d \pmod x\),且 \(f_1 = f_n = 0\)。\(f_i\) 的实际意义是,\(1 \to i\) 的所有路径的权值和模 \(x\) 的值。

但是这题不是边权而是点权。考虑拆点,在新图上连边 \(u \to u'\),边权 \(a_u\);\(u' \to u\),边权 \(-a_u\);原图 \(u \to v\) 的边在新图上连边 \(u' \longleftrightarrow v\),边权 \(0\)。那么判是否存在一组 \(\{f_n\}\) 等价于新图的所有环权值和模 \(x\) 意义下都是 \(0\)。

新图若忽略边权实际上是一张无向图。所以跑出新图的一棵 dfs 树,设根到 \(i\) 的路径边权和为 \(g_i\)。若设一条非树边为 \(u \to v\),边权为 \(d\),那么需要满足 \(g_u - g_v + d \equiv 0 \pmod x\)。所以 \(x\) 是所有这样的 \(|g_u - g_v + d|\) 的因数。那么把所有 \(|g_u - g_v + d|\) 取 \(\gcd\) 就是答案。

还有个问题是点权可能不确定。点权不确定的点就不连 \(u\) 和 \(u'\) 之间的边。这样新图可能不连通,跑出一个 dfs 森林即可。

code
// Problem: E - GCD of Path Weights
// Contest: AtCoder - AtCoder Regular Contest 144
// URL: https://atcoder.jp/contests/arc144/tasks/arc144_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 600100;

ll n, m, a[maxn], ans, f[maxn], dep[maxn];
vector<int> G[maxn], rG[maxn];
vector<pii> T[maxn];
pii E[maxn];
bool vis1[maxn], vis2[maxn], vis[maxn];

void dfs1(int u) {
	vis1[u] = 1;
	for (int v : G[u]) {
		if (!vis1[v]) {
			dfs1(v);
		}
	}
}

void dfs2(int u) {
	vis2[u] = 1;
	for (int v : rG[u]) {
		if (!vis2[v]) {
			dfs2(v);
		}
	}
}

void dfs(int u) {
	vis[u] = 1;
	for (pii p : T[u]) {
		ll v = p.fst, d = p.scd;
		if (!vis[v]) {
			f[v] = f[u] + d;
			dep[v] = dep[u] + 1;
			dfs(v);
		} else if (dep[v] < dep[u]) {
			ans = __gcd(ans, abs(f[u] - f[v] + d));
		}
	}
}

void solve() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1, u, v; i <= m; ++i) {
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		rG[v].pb(u);
		E[i] = mkp(u, v);
	}
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
	}
	dfs1(1);
	dfs2(n);
	for (int i = 1; i <= n; ++i) {
		if (a[i] != -1 && vis1[i] && vis2[i]) {
			T[i].pb(i + n, a[i]);
			T[i + n].pb(i, -a[i]);
		}
	}
	for (int i = 1; i <= m; ++i) {
		int u = E[i].fst, v = E[i].scd;
		if (vis1[u] && vis2[u] && vis1[v] && vis2[v]) {
			T[u + n].pb(v, 0);
			T[v].pb(u + n, 0);
		}
	}
	T[1].pb(n + n, 0);
	T[n + n].pb(1, 0);
	for (int i = 1; i <= n * 2; ++i) {
		int j = (i > n ? i - n : i);
		if (!vis[i] && vis1[j] && vis2[j]) {
			dfs(i);
		}
	}
	printf("%lld\n", ans == 0 ? -1LL : ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,144,GCD,int,边权,typedef,long,maxn,ans
From: https://www.cnblogs.com/zltzlt-blog/p/17850032.html

相关文章

  • [AtCoder Toyota2023 Spring Final] Git Gud
    拜谢MagicDuck大神。其次我很喜欢洛谷逆天翻译把大翻译成小……首先考虑算一下贡献,考虑每个点的深度,一开始都是1,进行合并以后相当于首先把两个端点的深度累计到答案里,然后再选择一边给它的联通块内每个点深度增加1。那么容易发现我们可以算贡献转化为每个联通块权值为它向外......
  • AtCoder Beginner Contest 329
    劳累一天不该写题,启发式合并都写错了A-Spread(abc329A)题目大意给定一个字符串,将每个字符输出出来,中间留个空格。解题思路遍历输出即可。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;intmain(void){ios::sync_with_std......
  • loj144&145 dfs序+树状数组/线段树
    https://loj.ac/p/144https://loj.ac/p/145两题非常相似,一题的权值修改是在点上的,一题的权值修改是在整棵子树上的。首先我们要了解dfs序,并记录每个节点的子树大小sz,对于一个节点,在dfs序上sz长的区间全都是他的子节点以及他自己。所以我们将一棵树映射到了一个区间上,并且可......
  • AtCoder Beginner Contest(abc) 326
    B-326-likeNumbers难度:⭐题目大意如果一个三位数的百位和十位的乘积等于个位,那么这个数就是合法的;问大于等于n的最小的合法的数是多少;解题思路因为数据范围很小,所以可以直接暴力;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios......
  • AtCoder Beginner Contest 329
    C-Countxxx题意是:给你一个字符串,求出字符串里面相同字母的子串数量思路:用map映射即可,取每个字母的最大长度,然后加起来usingnamespacestd;intmain(){ intn; strings; cin>>n>>s; map<char,int>mp; intct=1; for(inti=1;i<n;i++){ if(s[i]!=s[i-1]){ mp[s[......
  • ARC144E GCD of Path Weights
    Description给定\(n\)个点,\(m\)条边的有向图,图中的任意一条有向边满足边起点的编号小于边终点的编号。每个点有点权,但其中有些点的点权未知。你需要找到一种给未知点权值的方案,使得所有\(1\ton\)的路径点权和的最大公因数最大,或者告知答案可以无限大。输出这个最大值。......
  • AtCoder Beginner Contest 329 (ABC329)
    A.Spread不说了,代码。B.Next不说了,代码。C.CountxxxDescription给定一个长度为\(N\)的字符串\(S\),求\(S\)中非空连续,并且包含重复字符的连续子串长度。例如$S=$aaabaa,则它满足上述条件子串为a,aa,aaa,b。Solution这道题\(1\leN\le2\times10^5\),显然......
  • 牛客小白月赛81 F 小辰刚学gcd
    LInk首先我们可以注意到,两个数的gcd要不是它们当中较小的那一个要不是它本身。所以对于一个特定的\(r\),\(gcd_{i=p}^r,1<=p<=r\)来说,答案不会超过32种。并且因为gcd的性质,答案一定是成块且递减的。所以我们可以直接记录下对于每一个\(r\),答案都有哪些,从哪里开始出现。并......
  • AtCoder Beginner Contest(abc) 329
    B-Next难度:⭐题目大意给定n个数,输出其去重后的次大值;解题思路暴力就行;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios::sync_with_stdio(false),cin.tie(0),cout.tie(0)#defineendl'\n'usingnamespacestd;constintN=2e......
  • AtCoder Beginner Contest(abc) 296
    B-Chessboard难度:⭐题目大意给定一个8*8的字符矩阵,其中只有一个'*',输出它的坐标;其坐标的列用字母表示,行用数字表示,具体看样例解释;解题思路签到题不多嗦了;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios::sync_with_stdio......