首页 > 其他分享 >P5605 小 A 与两位神仙 题解

P5605 小 A 与两位神仙 题解

时间:2024-02-27 20:00:24浏览次数:22  
标签:神仙 ch P5605 int 题解 varphi while delta now

题意

  • 给定 \(x\)、\(y\) 和 \(m\),其中 \(m=p^n,n\in \mathbb{N+},p\ge3\),问同余方程 \(x^a\equiv y\pmod m\) 是否有非负整数解。

分析

前置芝士

化简

  • 对这种指数型的同余方程是很难解决的,我们要先把它转化成线性的同余方程。原式很讨人厌的一点就是 \(x\)、\(y\) 和 \(a\) 并不在同一个层次上,但是把 \(a\) 降下来很难 (主要是我不会),因此想到将 \(x\) 和 \(y\) 升到幂的位置上,由此联想到原根。根据原根的存在性判定我们知道 \(m\) 存在原根。令 \(g\) 为 \(m\) 的一个原根,\(i_x\) 表示使 \(g^i\equiv x\bmod m\) 成立的 \(i\) 值,于是有

\[x^a\equiv y\pmod m \]

等价于

\[g^{i_xa}\equiv g^{i_y}\pmod m \]

等价于

\[i_xa\equiv i_y\pmod {\varphi(m)} \]

  • 这是一个线性同余方程,但是我们并不知道 \(i_x\) 和 \(i_y\) 的值具体为多少,所以这里需要进一步转化。上式等价于

\[\gcd(i_x,\varphi(m))\mid\gcd(i_y,\varphi(m)) \]

再由 \(\large\delta_m(x)=\delta_m(g^{i_x})=\frac{\varphi(m)}{\gcd(i_x,\varphi(m))}\) 可转化为

\[\frac{\varphi(m)}{\delta_m(x)}\mid\frac{\varphi(m)}{\delta_m(y)} \]

等价于

\[\delta_m(y)\mid\delta_m(x) \]

  • 于是原来的问题就转化为求解 \(\delta_m(x)\) 和 \(\delta_m(y)\) 了,这就简化很多了,可以直接求解。

求解

  • 求欧拉函数很简单,有多种解法,由于这里仅需要 \(m\) 这一个数的 \(\varphi\) 值,所以直接用 \(\varphi(p^k)=p^k-p^{k-1}\) 求解即可。对于 \(\delta_m(x)\),利用 \(\delta_m(x)\mid\varphi(m)\) 的性质直接对 \(\varphi(m)\) 进行质因数分解,一一试除即可。
  • 还有,下面代码用了 (__int128) 的乘法不用会爆 long long,会导致各种错误,我为了这个也就调了 3 个小时而已吧,后面实在不行就照着 Alex_Wei 大佬的代码重改了一遍才发现,血泪教训
  • 还有,求 \(\varphi(m)\) 的值我最初是用的 \(O(\sqrt n)\) 的单个求法的,交上去 TLE 了之后才意识到会时间爆炸,参考 Alex_Wei 大佬的代码后改用分解质因数的方法(也就是上面说的做法),这种做法的复杂度是 \(O(n^{\frac{1}4})\),快了不少(求完之后记得清空统计质因数的 map,调这玩意花了 30 分钟)。

AC 代码

#include <bits/stdc++.h>
#define int long long
#define inf 1e9
using namespace std;
int n, m, phi, x, y;
map<int, bool> mp;

inline void read(int &x) {
	char ch = x = 0;
	int m = 1;
	while (ch < '0' || ch > '9') {
		ch = getchar();
		if (ch == '-')
			m *= -1;
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + ch - 48;
		ch = getchar();
	}
	x *= m;
	return ;
}

int seed;
inline int rnd(int x) {
	int a = rand() % 1145 + 1;
	x *= a;
	x ^= x << 13;
	x ^= x >> 7;
	x ^= x << 17;
	x /= a;
	return abs(x);
}

int gcd(int a, int b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}

inline int ksmi(__int128 a, int b, int mod) {
	int s = 1;
	while (b) {
		if (b & 1) s = a * s % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return s;
}

inline bool mr(int n) {
	if (n < 3 || n % 2 == 0) return n == 2;
	int r = n - 1, d = 0;
	while ((r & 1) == 0) {
		r >>= 1;
		d++;
	}
	int a, v;
	for (int i = 1; i <= 20; i++) {
		a = seed = rnd(seed);
		a = a % (n - 2) + 2;
		v = ksmi(a, r, n);
		if (v == 1) continue;
		for (int j = 0; j <= d; j++) {
			if (j == d) return 0;
			if (v == n - 1) break;
			v = (__int128)v * v % n;
		}
	}
	return 1;
}

inline int pol(int n) {
	int s = 0, t = 0, now = 1, c = seed = rnd(seed);
	c = c % (n - 1) + 1;
	int k = 1;
	while (1) {
		for (int j = 1; j <= k; j++) {
			t = ((__int128)t * t + c) % n;
			now = (__int128)now * abs(s - t) % n;
			if ((j % 127 == 0 || j == k) && gcd(now, n) > 1) return gcd(now, n);
		}
		s = t;
		k <<= 1;
	}
}

void fac(int n) {
	if (n == 1) return;
	if (mr(n)) {
		mp[n] = 1;
		return ;
	}
	int p = n;
	while (p == n) p = pol(n);
	while (n % p == 0) n /= p;
	fac(p);
	fac(n);
	return ;
}

signed main() {
	srand((unsigned)time(0));
	seed = rand() * rand();
	read(m), read(n);
	fac(m);
	int pri = mp.begin() -> first;
	phi = m - (m / pri);
	mp.clear();
	fac(phi);
	int ordx, ordy, now;
	while (n--) {
		read(x), read(y);
		ordx = ordy = phi;
		for (auto it : mp) {
			now = it.first;
			while (ordx % now == 0 && ksmi(x, ordx / now, m) == 1) ordx /= now;
			while (ordy % now == 0 && ksmi(y, ordy / now, m) == 1) ordy /= now;
		}
		if (ordx % ordy) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}

标签:神仙,ch,P5605,int,题解,varphi,while,delta,now
From: https://www.cnblogs.com/iloveoi/p/18037725

相关文章

  • [ARC121B] RGB Matching 题解
    题意有\(2N\)个物品,每个物品有可爱度\(a_i\)和颜色\(c_i\),将其两两配对。假设物体\(i\)和\(j\)配对,则\(c_i\neqc_j\),则会增加\(|a_i-a_j|\)的不满意度,求最小的不满意度。分析这道题可以贪心解决。我们尽量让每一对物品颜色相同,令每种颜色的总个数为\(cnt_c\),......
  • AT_abc270_g [ABC270G] Sequence in mod P 题解
    [ABC270G]SequenceinmodP博客阅读可能体验更佳题意给出递推式如下,求最小的使\(X_i=G\)成立的\(i\)。\[X_i=\begin{cases}S&i=0\\(A\timesX_{i-1}+B)\bmodp&i\ge1\end{cases}\]分析这里分几种情况来分析:当\(A=0\)时,\(X_i\)要么等于\(S\),要么等于\(B\),直......
  • CF1928C Physical Education Lesson 题解
    洛谷传送门原题传送门题意一种上下波动的数组,给出所在的位置\(n\)和对应的数字\(x\),求出有几种数组满足条件。令\(k\)为最大值,则数组长成这样子:\[1,2,3,\cdots,k-1,k,k-1,k-2,\cdots,2,1,2,3,\cdots\]如图,每\(2(k-1)\)就循环一次。分析因为每\(2(k-1)\)......
  • CF1477A Nezzar and Board 题解
    题意给出数列\(S=\{a_i\}\)和整数\(k\),求是否能通过下面的操作使得\(k\inS\)?操作:选取\(x,y\inS\),将\(2x-y\)加入\(S\)中。分析观察操作可以发现,\(2x-y\)实际上就是数轴上\(y\)关于\(x\)的对称点,因此这个操作只与\(x\)和\(y\)在数轴上的相对位置有关,与......
  • [ABC342D] Square Pair 题解
    洛谷传送门原题传送门题意给出一个数列\(A\),求出满足\(A_iA_j\)为完全平方数的无序数对\((i,j)\)的个数。分析容易想到(但是我在昨晚没想到,可以原地AFO了),对于每个数,如果是\(0\)的话可以直接统计答案(记录\(0\)的个数\(cnt\),最后\(ans\leftarrowans+cnt(n-cnt)+\f......
  • [ABC342E] Last Train 题解
    洛谷传送门原题传送门题意给出一些由\((l,d,k,c,A,B)\)描述的列车,表示每当时间为\(l,l+d,l+2d,\cdots,l+(k-1)d\)时有一半列车从\(A\)出发,经过\(c\)的时间到达\(B\)。问如果从站点\(i,i\in(0,n)\)出发要去站点\(n\),最晚什么时候到达站点\(i\)可以去到站点\(n\)......
  • [ABC342C] Many Replacement 题解
    洛谷传送门原题传送门题意给出由小写字母初始字符串,每次操作将字符串中所有为\(c\)的字符改为\(d\)。输出最终的字符串。分析很明显只需要开一个\(fa\)数组,其中\(fa[i]=j\)表示字母\(i\)被改为了\(j\)。对于每次操作只需要遍历\(26\)个字母,将\(fa[i]=c\)的那些......
  • [ABC341E] Alternating String 题解
    题目传送门原题传送门题意给出长为\(n\)的01串,如果一个子串01交替出现,则称其为“好的”。有\(q\)次询问,把\([x,y]\)中的每一位反转或者询问\([x,y]\)是否是“好的”。分析一眼线段树。用线段树维护区间是否是“好的”,每个节点维护最左段和最右端的值,pushup和q......
  • [ABC342G] Retroactive Range Chmax 题解
    洛谷传送门原题传送门题意维护一个数列,有以下三个操作:区间最值操作,即将\([l,r]\)区间内的\(A_i\)变成\(\max(A_i,v)\)。删除操作操作,即将第\(i\)次操作删除,保证第\(i\)次操作是操作\(1\),且未被删除。注:仅删除第\(i\)次操作,后续操作仍然在。查询,询问当前的......
  • P1013 进制位 题解
    题注题目传送门这篇题解其实是上一篇题解(Llf0703同志)证明过程的完善(其实就是思路一样了啦),来让入门者或追求严谨者对证明过程更加了解。题目分析\(3\leqn\leq9\),也即数字的个数\(N\leq8\)。研究样例发现,\(N\)与进制\(R\),以及数字对应两位数个数\(M\)与数字本身......