题目传送门

  传送门

Subtask 1

  直接模拟。

Subtask 2

  BSGS算法模板。

Subtask 3

  考虑模 $m$ 的任意一个原根 $g$。

  假设 $g^{ra} \equiv x \pmod {m}, g^{rb} \equiv y \pmod{m}$ 。

  那么原题的方程等价于方程 $a \cdot ra \equiv rb \pmod {\varphi(m)}$。

  它等价于 $x \cdot ra - y\cdot \varphi(m) = rb$。

  设 $d = \varphi(m)$。

  它存在满足条件的解当且仅当 $(ra, d) \mid rb$。

  这个条件仍然不好处理,因为我们难以求出 $rb$。

  考虑这样一个条件 $(ra, d) \mid (rb, d)$。

  我们来证明,满足 $(ra, d) \mid rb$ 当且仅当 $(ra, d) \mid (rb, d)$。

  充分性显然。

  考虑必要性,因为 $((ra,d), (rb,d)) = (ra, rb, d) = ((ra, d) , rb) = (ra, d)$。

  所以有 $(ra, d) \mid (rb, d)$。

  现在的问题是如何求 $(ra, d)$。

引理 设 $g$ 为模 $m$ 意义下的一个原根 ,如果 $g^{ra} \equiv a \pmod {m}$,设 $\delta_m(a) = d$ ,那么有 $(ra, \varphi(m)) d = \varphi(m)$.

  证明 因为有 $\left( g^{ra}\right)^d \equiv 1\pmod{m}$,所以 $\varphi(m) | ra \cdot d$。

  那么有 $ra \cdot d \equiv 0 \pmod {\varphi(m)}$.

  所以有 $d \equiv 0 \pmod{\frac{\varphi(m)}{(\varphi(m), ra)}}$.

  因为 $d$ 是满足条件的最小正整数,所以有 $d = \frac{\varphi(m)}{(\varphi(m), ra)}$。

  所以 $(\varphi(m), ra) d = \varphi(m)$。

  因此我们把问题转化为求阶。

  众所周知,阶是 $\varphi(m)$ 的约数,所以我们暴力枚举所有因子能通过这个subtask。

Subtask 4

  因为 $p$ 随机,所以期望的因子个数只有几千,做法同 Subtask 3。

Subtask 5

  骗暴力选手去卡常。

Subtask 6

  我们考虑优化求阶的做法。

引理 设 $d = \delta_m(x)$,如果 $d_0$ 满足 $x^{d_0} \equiv 1\pmod {m}$,那么有 $d | d_0$。

  证明 设 $d_0 = qd + r\ (0 < r < d)$。那么有 $x^{qd + r} \equiv (x^{d})^q x^r \equiv x^r \equiv 1\pmod{m}$。因为 $d$ 是最小的正整数满足 $x^{d} \equiv 1 \pmod {m}$,但 $r$ 是更小的满足条件的正整数,这和阶的定义矛盾。

  初始令 $d =\varphi(m)$。根据欧拉定理,我们知道一定有 $x^{d} \equiv 1 \pmod{m}$。设 $d = k\delta_m(x)$

  考虑枚举任意一个 $\varphi(m)$ 的质因子 $p$,如果满足 $p \mid d$,并且 $x^{d / p} \equiv 1 \pmod {m}$。 那么有 $p \mid k$,我们令 $d' = d / p$ 继续执行这个过程,直到不存在满足条件的 $p$。

  由于乘法取模我们可以使用 __int128 ,所以时间复杂度 $O(T \log^2 V + n^{1/4})$。

  如果同时求 $(ra, \varphi(m)), (rb, \varphi(m))$ 可能会被卡常。

Subtask 7

  我们注意到,我们没有必要求 $(rb, \varphi(m))$。

  设 $d = \varphi(m)$。

  $(ra, d) | (rb, d) $ 等价于 $\frac{d}{(rb, d)}| \frac{d}{(ra, d)}$。

  因此我们只用判断 $b^{e}$ 模 $m$ 的余数是否为1就行了。

  其中 $e$ 是最小的正整数满足 $a^e \equiv 1 \pmod{m}$,即 $a$ 模 $m$ 的阶。

吐槽

  • 不知道为什么很多人觉得 $(ra, d) \mid rb$ 当且仅当 $(ra, d) \mid (rb, d)$ 非常地显然,可能是我数学比较菜,觉得不是那么显然,需要说明一下。
  • 成功区分了会求阶和不会求阶的选手
  • 开始想卡掉求 2 次阶的做法,因为 F 很难,为了降低比赛难度,所以被要求这里不卡常,不过好像卡不卡区分度都是一样的。
  • 事后发现,二进制分组和 long double 快速乘均可以轻松跑进两倍标程序时限内,感觉我对卡常一无所知,我似乎还忘了卡 long double 快速乘。(虽然我并不知道能个不能卡)。两倍常数还想卡?
  • 洛谷怎么最大只支持 100 组数据

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long
#define ull unsigned long long template <typename T>
T add(T a, T b, T m) {
return ((a += b) >= m) ? (a - m) : (a);
} template <typename T>
void pcopy(T* pst, const T* ped, T* pval) {
for ( ; pst != ped; *(pst++) = *(pval++));
} ll mul(ll a, ll b, ll m) {
return ((__int128)a) * b % m;
/* ll rt = 0, pa = a;
for ( ; b; b >>= 1, pa = add(pa, pa, m))
if (b & 1)
rt = add(rt, pa, m);
return rt; */
} ll qpow(ll a, ll p, ll m) {
ll rt = 1, pa = a;
for ( ; p; p >>= 1, pa = mul(pa, pa, m))
if (p & 1)
rt = mul(rt, pa, m);
return rt;
} ll gcd(ll a, ll b) {
return (b) ? (gcd(b, a % b)) : (a);
} ll randLL() {
static ull seed = 998244353, msk = (1ull << 61) - 1;
return (signed ll) ((seed = seed * seed + seed * 3 + 233) & msk);
} boolean miller_rabin(ll n) {
static int T = 25;
static const int pri[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
if (!(n & 1))
return n == 2;
if (n < 1000) {
for (int p = 2; p * p <= n; p++)
if (!(n % p))
return false;
return true;
}
for (int i = 0; i < 10; i++) {
if (n == pri[i]) {
return true;
} else if (!(n % pri[i])) {
return false;
}
}
ll d = n - 1;
int s = 0;
while (!(d & 1))
s++, d >>= 1;
for (int t = 0; t < T; t++) {
ll b = randLL() % n;
if (!b)
continue;
ll tmp = qpow(b, d, n);
if (tmp == 1 || tmp == n - 1)
continue;
for (int i = 0; i < s; i++) {
tmp = mul(tmp, tmp, n);
if (tmp == n - 1)
goto nextTurn;
if (tmp == 1 || tmp == 0)
return false;
}
if (tmp != 1)
return false;
nextTurn:;
}
return true;
} ll pollard_rho(ll x) {
// cerr << x << '\n';
ll a, b, c, g;
if (!(x & 1))
return 2;
while (true) {
b = a = randLL() % x;
c = randLL() % 127 % x;
do {
a = add(mul(a, a, x), c, x);
b = add(mul(b, b, x), c, x);
b = add(mul(b, b, x), c, x);
g = gcd(b - a, x);
(g < 0) ? (g = -g) : (0);
if (g == x)
break;
if (g > 1)
return g;
} while (a != b);
}
assert(false);
return 0;
} void get_primary_factors(ll x, vector<ll>& rt) {
if (x == 1) {
return;
}
if (miller_rabin(x)) {
rt.push_back(x);
return;
}
ll a = pollard_rho(x);
get_primary_factors(a, rt);
get_primary_factors(x / a, rt);
} vector< pair<ll, int> > get_primary_factor(vector<ll>& vec) {
vector< pair<ll, int> > rt;
if (vec.empty())
return rt;
sort(vec.begin(), vec.end());
vector<ll>::iterator it = vec.begin();
rt.push_back(make_pair(*it, 1));
for (it = it + 1 ; it != vec.end(); it++)
if (*it == rt.back().first)
rt.back().second++;
else
rt.push_back(make_pair(*it, 1));
return rt;
} /// Template ends typedef vector<pair<ll, int>> factor; factor get_factor(ll m) {
vector<ll> tmp;
get_primary_factors(m, tmp);
return get_primary_factor(tmp);
} int T;
ll m, phim;
factor fac; int main() {
scanf("%lld%d", &m, &T);
fac = get_factor(m);
fac = get_factor(phim = m / fac[0].first * (fac[0].first - 1));
ll a, b, d;
while (T--) {
scanf("%lld%lld", &a, &b);
d = phim;
for (auto par : fac) {
while (!(d % par.first) && qpow(a, d / par.first, m) == 1)
d /= par.first;
}
if (qpow(b, d, m) == 1) {
puts("Yes");
} else {
puts("No");
}
}
return 0;
}

luogu P5605 小 A 与两位神仙 - 原根的更多相关文章

  1. js限制输入数字能输入小数点,js定义数组,js往数组中添加数据,js将字符型转为数字型,除法结果保留两位小数——js小测:计算比赛得分

    一个朋友跟我说要去给某个比赛算分: 规则:去掉最低分最高分求平均分: 最近在学习大数据可视化——图谱,用到js一些东西,所以今天就用js练练 用到知识点: js限制输入数字能输入小数点,js定义数组, ...

  2. Android限定EditText的输入类型为数字或者英文(包括大小写),EditText,TextView只能输入两位小数

    Android限定EditText的输入类型为数字或者英文(包括大小写) // 监听密码输入框的输入内容类型,不可以输入中文    TextWatcher mTextWatcher = new Tex ...

  3. C语言中两位ASCII码可以表示汉字

    最近偶然有人问到这个相关字符编码的问题,所以百度了下参考了这两个资料,进行了简单分析. ******************************************************** ...

  4. JAVAWEB 生成excel文字在一格显示两位不变成#号

    在用java生成excel的时候会发现这种问题, 如果是人家给的模板还好,如果不是模板,而是通过代码生成的话, 就需要进行处理了, 一个小单元格,如果是一位的话,如1-9显示没有问题,一旦是两位的话, ...

  5. php小数点后取两位的三种实现方法

    php小数点后取两位的方法. 方法一.经常用到小数点后取几位,但不能进位的情况. 比如3.149569取小数点后两位,最后两位不能四舍五入.结果:3.14. 可以使用函数floor. 该函数是舍去取整 ...

  6. python(62):保留两位小数

    转载:https://blog.csdn.net/jiandanjinxin/article/details/77752297 在C/C++语言对于整形数执行除法会进行地板除(舍去小数部分). 例如 ...

  7. BigDecimal的用法详解(保留两位小数,四舍五入,数字格式化,科学计数法转数字,数字里的逗号处理)

    转自:https://blog.csdn.net/ochangwen/article/details/51531866 一.简介 Java在java.math包中提供的API类BigDecimal,用 ...

  8. [Linux]运维三十六计--腾讯两位大神的总结

    这里是腾讯两位大神梁定安.周小军总记得运维DBA三十六计,So有道理

  9. luogu P1373 小a和uim之大逃离

    题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个 ...

随机推荐

  1. VMware workstation 12虚拟机安装CentOS7详细安装教程

    虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算机系统. 虚拟系统通过生成现有操作系统的全新虚拟镜像,它具有真实windows系统完全 ...

  2. .Net轻松处理亿级数据--clickhouse及可视化界面安装介绍

    该篇内容由个人博客点击跳转同步更新!转载请注明出处! 前言 我是在17年就听说过Clickhouse,那时还未接触过亿数据的运算,那时我在的小公司对于千万数据的解决方案还停留在分库分表,最好的也是使用 ...

  3. JWT攻击手册

    JSON Web Token(JWT)对于渗透测试人员而言可能是一种非常吸引人的攻击途径,因为它们不仅是让你获得无限访问权限的关键,而且还被视为隐藏了通往以下特权的途径:特权升级,信息泄露,SQLi, ...

  4. VOC数据集 目标检测

    最近在做与目标检测模型相关的工作,很多都要求VOC格式的数据集. PASCAL VOC挑战赛 (The PASCAL Visual Object Classes )是一个世界级的计算机视觉挑战赛, P ...

  5. YII 项目部署时, 显示空白内容

    本地开发完成,想部署到服务器上,选用了GIT来在服务器上获取上传的本地项目,结果clone后,访问网址后,YII就是个空白页,啥信息也没有,无语.. 刚开始以为是权限问题,后来给访问的目录加了777, ...

  6. Scrapy-Splash简介及验证码的处理(一)

    目录 一:Splash简介与准备 二:验证码的识别(1)   在之前的博客中,我们学习了selenium的用法,它是一个动态抓取页面的方法,但是,动态抓取页面还有其他的方法,这里介绍Splash方法, ...

  7. JVM 学习总结

    目录 Java内存区域 运行时数据区 & Java 内存结构 & Java 内存区域 1. 程序计数器 2. Java 虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区 6. 运行时 ...

  8. 「黑客必备技能」Python正则表达式详解

    说在前面 正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能. 正则表达式在不同的语言中使 ...

  9. 8 Best DDoS Attack Tools (Free DDoS Tool Of The Year 2019)

    #1) HULK Description: HULK stands for HTTP Unbearable Load King. It is a DoS attack tool for the web ...

  10. PMP备考-第一章-引论

    项目 项目是为创造独特的产品,服务和成果而进行的临时性工作.在规定的范围,进度,成本,和质量要求之下完成项目可交付成果. 项目与运用 项目 :临时性,独特性,渐进明细 运营 :持续的,相似性,标准化 ...