【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;
}