【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 所在的连通块里面所有边边权的 gcdg,一个显然的事情是 g|s,但这是必要,但不知道充不充分。


首先 uv 的路径可以表示乘 gx,假设这个路径经过了连通块里面所有的点,那任意一条边我们都可以通过(反复)横跳使得这条边被多走两次。
那我们设每条边的边权是 li,也就是我们要找一组正整数 xi 使得 i=1txilig(modm)(这样就可以组成所有要的位置)
那我们乘 1/g 就有 i=1txilig1(modmg)

那算上原本的要是 i=1t2yiligsgx(modmg)
yi=21((sgx+mg)modmg)xi
那有解的情况就是 2 有逆元,那就是要 gcd(2,mg)=1mg 是奇数。


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


那剩下的情况是 mg 是偶数且不存在 /g 的奇环。
那从前面我们推的地方就知道,条件应该是 xmod2=sgmod2


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

然后是如何处理查询。
那就是有多少个 0i<c 使得 g|(x+bi),或者 2g|(x+bi) 或者 (x+bi)mod2g=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; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day13_A.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2022-02-22 【luogu P6242】【模板】线段树 3(吉司机线段树)
2022-02-22 【NOI2021模拟测试赛(四十二)】D(cdq分治)(树状数组)
2022-02-22 【NOI2021模拟测试赛(四十二)】chemistry(珂朵莉树)(动态开点线段树)
2021-02-22 【luogu P3690】【模板】Link Cut Tree (动态树)
2021-02-22 【luogu P3384】【模板】轻重链剖分
2021-02-22 【ybt金牌导航5-1-1】【luogu P2590】树的统计
2021-02-22 【ybt金牌导航4-5-1】【luogu P3369】普通平衡树(替罪羊树做法)
点击右上角即可分享
微信分享提示