bzoj4802 欧拉函数(附Millar-Rabin和Pollard-Rho讲解)
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4802
【题解】
参考:http://www.matrix67.com/blog/archives/234
Millar-Rabin质数检验方法:
根据费马小定理,如果p是素数,a<p,那么有a^(p-1) mod p = 1。
直观想法我们直接取若干个a,如果都有一个不满足,那么p就是合数。
遗憾的是,存在Carmichael数:你无论取多少个a,有一个不满足,算我输。
比如:561 = 11*51就是一个Carmichael数。
那么就很江了啊。。我们需要改进算法。
首先有:如果p是素数,x是小于p的正整数,且x^2 mod p = 1,那么要么x=1,要么x=p-1
(这个废话,x=p-1模意义下等于x=-1)
然后我们可以展示下341满足2^340 mod 341 = 1,却不是素数(341=31*11)的原因:
2^340 mod 341 = 1
2^170 mod 341 = 1
2^85 mod 341 = 32
(32这个数很py啊怎么不等于340也不等于1啊。。这明显有交易嘛)
那么就能说明这个数不是素数。
如果是素数,一定是从p-1变到1,或是把所有2的次幂去除完,本来就等于1(这样平方完就一直是1了)
所以要么把所有2的次幂去除完,本来就等于1,要么存在某一个次幂=p-1(这样就正常多了)
这就是Millar-Rabin素数验证的二次探测。
应该来说Millar-Rabin算法也是挺好写的
其中mul(a,b,c)表示a*b%c(因为a*b会爆longlong,所以用快速加)
namespace Millar_Rabin {
const int Prime[] = {, , , , , , , , , , , , , };
const int PN = ; inline bool witness(int pr, ll res, int times, ll n) {
ll p = pwr2((ll)pr, res, n);
if(p == ) return ;
for (int i=; i<times; ++i) {
if(p == n-) return false;
if(p == ) return false;
p = mul(p, p, n);
}
return true;
} inline bool main(ll n) {
for (int i=; i<=PN; ++i) {
if(n == Prime[i]) return ;
if(n % Prime[i] == ) return ;
}
ll p = n-;
int times = ;
while(!(p&)) {
++times;
p >>= ;
}
for (int i=; i<=PN; ++i)
if(witness(Prime[i], p, times, n)) return false;
return true;
}
}
然后我们会检验素数了,现在要质因数分解。
好了下一个是Pollard-Rho算法:
如果现在拆分的是n:Pollard-Rho(n)
主要流程:Millar-Rabin判断是否质数,是返回,否就试图找出其中一个因子d,然后递归做Pollard-Rho(d)和Pollard-Rho(n/d)。
我猜你会说废话这谁都会。问题在于:试图找出其中一个因子d
参考:https://wenku.baidu.com/view/3db5c7a6ad51f01dc381f156.html?from=search
参考文章讲的非常详细了。。我就不细讲了qwq
所以这题就是分解因数,按照欧拉函数定义式求解即可。
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h> using namespace std; typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + ;
const int mod = 1e9+; # define RG register
# define ST static inline ll mul(ll a, ll b, ll mod) {
ll ret = ;
a %= mod, b %= mod;
while(b) {
if(b&) {
ret = ret + a;
if(ret >= mod) ret -= mod;
}
a <<= ;
if(a >= mod) a -= mod;
b >>= ;
}
return ret;
} inline ll pwr2(ll a, ll b, ll mod) {
ll ret = ;
a %= mod;
while(b) {
if(b&) ret = mul(ret, a, mod);
a = mul(a, a, mod);
b >>= ;
}
return ret;
} inline ll gcd(ll a, ll b) {
return b== ? a : gcd(b, a%b);
} namespace Millar_Rabin {
const int Prime[] = {, , , , , , , , , , , , , };
const int PN = ; inline bool witness(int pr, ll res, int times, ll n) {
ll p = pwr2((ll)pr, res, n);
if(p == ) return ;
for (int i=; i<times; ++i) {
if(p == n-) return false;
if(p == ) return false;
p = mul(p, p, n);
}
return true;
} inline bool main(ll n) {
for (int i=; i<=PN; ++i) {
if(n == Prime[i]) return ;
if(n % Prime[i] == ) return ;
}
ll p = n-;
int times = ;
while(!(p&)) {
++times;
p >>= ;
}
for (int i=; i<=PN; ++i)
if(witness(Prime[i], p, times, n)) return false;
return true;
}
} namespace PollardRho {
const int N = ;
ll q[N]; int qn; inline void PR(ll n) {
if(Millar_Rabin::main(n)) {
q[++qn] = n;
return ;
}
ll a, b, c, del;
while() {
c = rand() % n;
a = b = rand() % n;
b = (mul(b, b, n) + c) % n;
while(a != b) {
del = a-b;
del = gcd(abs(del), n);
if(del > && del < n) {
PR(del); PR(n/del);
return ;
}
a = (mul(a, a, n) + c) % n;
b = (mul(b, b, n) + c) % n;
b = (mul(b, b, n) + c) % n;
}
}
} inline ll getphi(ll n) {
if(n == ) return 1ll;
sort(q+, q+qn+);
ll res = q[] - ;
for (int i=; i<=qn; ++i) {
if(q[i] != q[i-]) res = res * (q[i] - );
else res = res * q[i];
}
return res;
} inline void main(ll n) {
qn = ;
PR(n);
cout << getphi(n) << endl;
}
} int main() {
srand();
ll n; cin >> n;
if(n == ) {
puts("");
return ;
}
PollardRho::main(n);
return ;
}
bzoj4802 欧拉函数(附Millar-Rabin和Pollard-Rho讲解)的更多相关文章
- BZOJ4802:欧拉函数(Pollard-Rho,欧拉函数)
Description 已知N,求phi(N) Input 正整数N.N<=10^18 Output 输出phi(N) Sample Input 8 Sample Output 4 Soluti ...
- BZOJ4802 欧拉函数 (Pollard-Rho Miller-Robin)
题目 求大数的欧拉函数φ\varphiφ 题解 Pollard-Rho 板子 CODE #pragma GCC optimize (3) #include <bits/stdc++.h> ...
- [日常摸鱼]bzoj4802 欧拉函数-PollardRho大整数分解算法
啊居然要特判,卡了好久QAQ (好像Windows下的rand和Linux下的不一样? QwQ一些东西参考了喵铃的这篇blog:http://www.cnblogs.com/meowww/p/6400 ...
- BZOJ4802 欧拉函数 数论
原文链接http://www.cnblogs.com/zhouzhendong/p/8117744.html 题目传送门 - BZOJ4802 题意概括 Description 已知N,求phi(N) ...
- 2018.12.17 bzoj4802: 欧拉函数(Pollard-rho)
传送门 Pollard−rhoPollard-rhoPollard−rho模板题. 题意简述:求ϕ(n),n≤1e18\phi(n),n\le 1e18ϕ(n),n≤1e18 先把nnn用Pollar ...
- [BZOJ4802]欧拉函数
bzoj description 给出\(n\),求\(\varphi(n)\).\(n\le10^{18}\) sol \(Pollard\ Rho\),存个代码. code #include< ...
- 【BZOJ4802】欧拉函数(Pollard_rho)
[BZOJ4802]欧拉函数(Pollard_rho) 题面 BZOJ 题解 这么大的范围肯定不好杜教筛. 考虑欧拉函数的计算式,显然只需要把\(n\)分解就好了. 直接\(Pollard\_rho\ ...
- 数学基础IV 欧拉函数 Miller Rabin Pollard's rho 欧拉定理 行列式
找了一些曾经没提到的算法.这应该是数学基础系最后一篇. 曾经的文章: 数学基础I 莫比乌斯反演I 莫比乌斯反演II 数学基础II 生成函数 数学基础III 博弈论 容斥原理(hidden) 线性基(h ...
- BZOJ2186 欧拉函数
欧拉函数:一般记作φ(n),表示1-n中与n互质的数的数量. 欧拉函数是积性函数,即φ(m*n)=φ(m)*φ(n) //这条定理基友面试时还遇到了= = 欧拉函数的值φ(n)=n*(1-p[1])* ...
随机推荐
- Delphi中统一显示表格字段名的高效方法
问题描述:在开发数据库程序时,我们经常要使用很多的表格显示组件DBGrid.当DBGrid显示某表格的数据时,其字段标题默认的就是后台数据库中的表格的字段名称.而为了数据库开发方便,后台数据库中的表格 ...
- 【转】Caffe的solver文件配置
http://blog.csdn.net/czp0322/article/details/52161759 solver.prototxt 今天在做FCN实验的时候,发现solver.prototxt ...
- UOJ #76 【UR #6】懒癌
确实是一道很不错的题啊. 题目链接 题意 感觉也没什么特别简洁的版本,大家直接看题面吧. 题解 我第一次看到这个类似问题的背景是疯狗,因此下面的题解不自觉的代入了...大家明白意思就好. 我们考虑对于 ...
- Linux学习之/etc/init.d/目录和rc.local脚本
init.d目录中包含很多系统服务的启动和停止脚本,比较常用的就是网络服务,当你修改了网络配置时,可以自行 sudo /etc/init.d/networking restart 命令来重启网络服务 ...
- BZOJ3998 TJOI2015弦论(后缀数组+二分答案)
先看t=1的情况.显然得求出SA(因为我不会SAM).我们一位位地确定答案.设填到了第len位,二分这一位填什么之后,在已经确定的答案所在的范围(SA上的某段区间)内二分,找到最后一个小于当前串的后缀 ...
- python成长之路五-文件操作
1,文件操作 f = open("D:\种子.txt",encoding="utf-8",mode="r") # 打开一个种子.txt文件, ...
- Java 8 的 Metaspace
Java 8 的 Metaspace https://www.cnblogs.com/xrq730/p/8688203.html 被废弃的持久代 想起之前面试的时候有面试官问起过我一个问题:Java ...
- 【总结】 Lucas定理
\(Lucas\)定理: \(C^x_y≡C^{x/p}_{y/p}*C^{x\%p}_{y\%p} ~~(mod~p)\) 证明不会2333 void pre(){ A[0]=A[1]=B[0]=B ...
- Python的双向链表实现
思路 链表由节点组成,先规定节点(Node),包含data和指向下个节点的next 初始化 data当然就是传入的data了,next和prev指向None 添加 分两种情况: 链表为空,那么头节点和 ...
- Hdoj 基本输入输出8道(1089-1096)
Hdoj 1089 #include<bits/stdc++.h> using namespace std; int main() { int a,b; while(cin>> ...