【YBT2023寒假Day13 A】鲁班七号(同余)(并查集)(分类讨论)

鲁班七号

题目链接:YBT2023寒假Day13 A

题目大意

给你一个 n 个点的无向图,一开始没有边。
给你一个数 m 和一些操作,操作有两点之间连一条给出边权的边,和给出 u,v,x,b,c,设 fi=x+bi,问又多少个 0<=i<c 满足图中有一条 u 到 v 的路径使得边权和与 fi 关于 m 同余。
路径可以不是简单路径。

思路

考虑看 \(u,v\) 之间路径边权和可以是 \(s\) 的条件。
那首先 \(u,v\) 所在的连通块里面所有边边权的 \(\gcd\)\(g\),一个显然的事情是 \(g|s\),但这是必要,但不知道充不充分。


首先 \(u\)\(v\) 的路径可以表示乘 \(gx\),假设这个路径经过了连通块里面所有的点,那任意一条边我们都可以通过(反复)横跳使得这条边被多走两次。
那我们设每条边的边权是 \(l_i\),也就是我们要找一组正整数 \(x_i\) 使得 \(\sum\limits_{i=1}^tx_il_i\equiv g\pmod m\)(这样就可以组成所有要的位置)
那我们乘 \(1/g\) 就有 \(\sum\limits_{i=1}^tx_i\dfrac{l_i}{g}\equiv 1\pmod {\frac{m}{g}}\)

那算上原本的要是 \(\sum\limits_{i=1}^t2y_i\dfrac{l_i}{g}\equiv \dfrac{s}{g}-x\pmod{\frac{m}{g}}\)
\(y_i=2^{-1}((\dfrac{s}{g}-x+\dfrac{m}{g})\bmod \dfrac{m}{g})x_i\)
那有解的情况就是 \(2\) 有逆元,那就是要 \(\gcd(2,\frac{m}{g})=1\)\(\dfrac{m}{g}\) 是奇数。


那我们继续考虑,如果 \(\dfrac{m}{g}\) 是偶数会怎样。
那当这个时候,同余方程不一定有解,那我们就要寻找另外的加边权方式。
会发现给的可能会有环,那用走奇环(注意这个奇偶是除了 \(g\) 之后的)来加也是一个方法。
就是当 \(x\bmod 2\neq \dfrac{s}{g} \bmod 2\) 我们给它加上一个大小为 \(gy\) 的奇环(\(y\) 为奇数)
就有 \((x+y)\bmod 2=\dfrac{s}{g}\bmod 2\)
那这个时候 \(g|s\) 也是充分的。


那剩下的情况是 \(\dfrac{m}{g}\) 是偶数且不存在 \(/g\) 的奇环。
那从前面我们推的地方就知道,条件应该是 \(x\bmod 2=\dfrac{s}{g}\bmod 2\)


那么接下来我们看如何求,我们所需要维护的是连通块里所有边边权的 \(\gcd\),以及是否存在奇环。
至于 \(\gcd\),我们可以直接用并查集维护连通块,直接维护每个并查集的 \(\gcd\) 即可。
至于判断奇环,会发现我们只用看二进制下的 \(0/1\),不过不能只看一位,因为会除 \(g\),所以我们可以记录每一位的 \(0/1\),那搞带权的并查集即可维护。

然后是如何处理查询。
那就是有多少个 \(0\leqslant i<c\) 使得 \(g|(x+bi)\),或者 \(2g|(x+bi)\) 或者 \((x+bi)\bmod 2g=g\)
这个就是一个同余方程,直接 exgcd 解,记得里面还有一个 \(x+bi\) 也要化就是了。

代码

#include <bits/stdc++.h>

const int S = 1 << 20;
char frd[S], *ihead = frd + S;
const char *itail = ihead;

inline char nxtChar()
{
	if (ihead == itail)
		fread(frd, 1, S, stdin), ihead = frd;
	return *ihead++;
}

template <class T>
inline void read(T &res)
{
	char ch; 
	while (ch = nxtChar(), !isdigit(ch));
	res = ch ^ 48;
	while (ch = nxtChar(), isdigit(ch))
		res = res * 10 + ch - 48;
} 

char fwt[S], *ohead = fwt;
const char *otail = ohead + S;

inline void outChar(char ch)
{
	if (ohead == otail)
		fwrite(fwt, 1, S, stdout), ohead = fwt;
	*ohead++ = ch;
}

template <class T>
inline void put(T x)
{
	if (x > 9)
		put(x / 10);
	outChar(x % 10 + 48);
}

//void read(int &res) {
//	scanf("%d", &res);
//} 
//
//void outChar(char ch) {
//	putchar(ch);
//}
//
//void put(int x) {
//	printf("%d", x);
//}

////浠ヤ笅涓虹ず渚?
//
//int main()
//{ 
//	int a, b;
//	read(a); read(b);
//	put(a + b), outChar('\n');
//}

using namespace std;

const int N = 1e6 + 100;
int n, m, q, fa[N], val[N][21], g[N];
bool tg[N][21];

int gcd(int x, int y) {
	if (!y) return x;
	return gcd(y, x % y);
}

int exgcd(int a, int b, int &x, int &y) {
	if (!b) {
		x = 1; y = 0;
		return a;
	}
	int re = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return re;
}

void down(int now) {
	if (now == fa[now]) return ;
	down(fa[now]);
	for (int i = 0; i <= 20; i++) val[now][i] ^= val[fa[now]][i];
}

int Find(int now) {
	if (fa[now] == now) return now;
	return fa[now] = Find(fa[now]);
}

int find(int now) {
	down(now); return Find(now);
}

void merge(int x, int y, int w) {
	int X = find(x), Y = find(y); g[X] = gcd(g[X], w);
	if (X == Y) {
		for (int i = 0; i <= 20; i++)
			if (val[x][i] ^ val[y][i] ^ ((w >> i) & 1)) tg[X][i] = 1;
	}
	else {
		for (int i = 0; i <= 20; i++)
			val[Y][i] = val[y][i] ^ ((w >> i) & 1) ^ val[x][i], tg[X][i] |= tg[Y][i];
		g[X] = gcd(g[X], g[Y]);
		fa[Y] = X;
	}
}

int work(int a, int b, int m, int r) {
	int d = gcd(a, m);
	if (b % d) return 0;
	int x, y; exgcd(a, m, x, y);
	x = (x + m) % m;
	long long X = 1ll * (b / d) * x; int bit = m / d;
	X = X % bit;//出第一个偏差的位置
	if (X > r) return 0;//出不到第一个
	return 1 + (r - X) / bit;
}

int main() {
	freopen("path.in", "r", stdin);
	freopen("path.out", "w", stdout);
	
	read(n); read(m); read(q);
	for (int i = 1; i <= n; i++) fa[i] = i;
	while (q--) {
		int op; read(op);
		if (op == 1) {
			int u, v, w; read(u); read(v); read(w);
			merge(u, v, w);
		}
		if (op == 2) {
			int u, v, x, b, c; read(u); read(v); read(x); read(b); read(c);
			if (find(u) != find(v)) {
				put(0); outChar('\n');
				continue;
			}
			int X = find(u), G = gcd(g[X], m);
			if ((m / G) & 1) put(work(b % G, (G - x % G) % G, G, c - 1));
				else {
					int k = 0, tmp = G; while (!(tmp & 1)) tmp >>= 1, k++;
					if (tg[X][k]) put(work(b % G, (G - x % G) % G, G, c - 1));
						else {
							if (val[u][k] ^ val[v][k]) put(work(b % (2 * G), (3 * G - x % (2 * G)) % (2 * G), 2 * G, c - 1));
								else put(work(b % (2 * G), (2 * G - x % (2 * G)) % (2 * G), 2 * G, c - 1));
						}
				}
			outChar('\n');
		}
	}
	
	fwrite(fwt, 1, ohead - fwt, stdout);
	return 0;
} 
posted @ 2023-02-22 15:20  あおいSakura  阅读(10)  评论(0编辑  收藏  举报