从BZOJ2242看数论基础算法:快速幂,gcd,exgcd,BSGS
其实就是三个板子
1.快速幂
快速幂,通过把指数转化成二进制位来优化幂运算,基础知识
2.gcd和exgcd
gcd就是所谓的辗转相除法,在这里用取模的形式体现出来
\(gcd(a,b)\),因为b中的a对答案没有贡献,考虑把b变成\(b-(b/a)*a\)答案是一样的
所以就可以变成了\(gcd(b,a%b)\),保证大的数在前面,这样当小的数变成0,大的数就是最大公约数
exgcd就是解线性方程\(ax+by=c\)
有解的条件是\(c\%gcd(a,b)=0\)
然后考虑gcd的过程对上面的方程进行转化
\(ax+by=gcd(a,b)=gcd(b,a\%b)=bx'+(a\%b)y'\)
这里把\(a%b\)变成\(a-a/b*b\),就变成了
\(ax+by=bx'+ay'-(a/b)*b*y'\)
解得\(x=y',y=x'-(a/b)*y'\)
然后当b变成1的时候,x=1,y=0
递归执行就可以解出来了
那么最小非负解是啥?
首先把x,y乘上\(c/gcd(a,b)\)变成原方程的特解
然后就可以得到通解
\(x = x' + b/gcd(a,b)*t\)
\(y = y' - a/gcd(a,b)*t\)
发现这个时候一定满足\(ax+by=c\),最小非负解也就很好求了
3.BSGS
挺有意思的一个东西,可以求解离散数对问题
\(a^x=b(mod\ c)\),给出a,b,c求x
大多数时候会保证c是质数
这个时候我们怎么办?
发现有用的x只有c-1个
考虑把x分解成ir+m的形式
然后式子变成\(a^{ir}=b*a^{-m}(mod\ c)\)
如果令\(r=\sqrt{c}\),那么枚举i并在hashtable里面查找有没有对应的m就可以了
这样的复杂度是\(\sqrt{c}\)的
//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
bool w = 1;x = 0;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = 0, c = getchar();
while (isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if (!w) x = -x;
}
template <typename T>
void Write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
int y, z, P;
int add(int a, int b) {
return (a += b) >= P ? a - P : a;
}
int sub(int a, int b) {
return (a -= b) < 0 ? a + P : a;
}
int mul(int a, int b) {
return 1ll * a * b % P;
}
int fast_pow(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = mul(res, a);
b >>= 1;
a = mul(a, a);
}
return res;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
void exgcd(int a, int b, ll &x, ll &y) {
if (!b) {x = 1, y = 0; return;}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
void work1() {
Read(y), Read(z), Read(P);
Write(fast_pow(y, z));
putchar('\n');
}
void work2() {
Read(y), Read(z), Read(P);
int g = gcd(y, P);
if (z % g) {
printf("Orz, I cannot find x!\n");
} else {
ll a, b;
exgcd(y, P, a, b);
a *= z / g;
a = (a % (P / g) + P / g) % (P / g);
Write(a);
putchar('\n');
}
}
map<int, int> mp;
void work3() {
Read(y), Read(z), Read(P);
y %= P, z %= P;
if (!y) {
printf("Orz, I cannot find x!\n");
return;
}
int w = sqrt(P), now = z;
mp.clear();
fu(i, 0, w) {
mp[now] = i;
now = mul(now, y);
}
now = fast_pow(y, w);
int tmp = now;
fu(i, 1, w) {
if (mp.count(tmp)) {
Write(i * w - mp[tmp]);
putchar('\n');
return;
}
tmp = mul(tmp, now);
}
printf("Orz, I cannot find x!\n");
}
int main() {
int T, op;
Read(T); Read(op);
if (op == 1) while (T--) work1();
else if (op == 2) while (T--) work2();
else while (T--) work3();
return 0;
}
从BZOJ2242看数论基础算法:快速幂,gcd,exgcd,BSGS的更多相关文章
- 【BZOJ4002】[JLOI2015]有意义的字符串(数论,矩阵快速幂)
[BZOJ4002][JLOI2015]有意义的字符串(数论,矩阵快速幂) 题面 BZOJ 洛谷 题解 发现我这种题总是做不动... 令\(A=\frac{b+\sqrt d}{2},B=\frac{ ...
- 【BZOJ2432】【NOI2011】兔农(数论,矩阵快速幂)
[BZOJ2432][NOI2011]兔农(数论,矩阵快速幂) 题面 BZOJ 题解 这题\(75\)分就是送的,我什么都不想写. 先手玩一下,发现每次每次出现\(mod\ K=1\)的数之后 把它减 ...
- 数论基础算法总结(python版)
/* Author: wsnpyo Update Date: 2014-11-16 Algorithm: 快速幂/Fermat, Solovay_Stassen, Miller-Rabin素性检验/E ...
- Java 算法-快速幂
1 什么是快速幂? 快速幂,顾名思义就是快速的求次幂,例如:a^b,普通的算法就是累乘,这样的计算方法的时间复杂度就是O(n),而快速幂的方法使得次幂的计算方法的时间复杂度降低到O(logn). 假 ...
- ACM | 算法 | 快速幂
目录 快速幂 快速幂取模 矩阵快速幂 矩阵快速幂取模 HDU1005练习 快速幂 幂运算:\(x ^ n\) 根据其一般定义我们可以简单实现其非负整数情况下的函数 定义法: int Pow ( ...
- 【POJ 1845】Sumdiv——数论 质因数 + 分治 + 快速幂
(题面来自luogu) 题目描述 输入两个正整数a和b,求a^b的所有因子之和.结果太大,只要输出它对9901的余数. 输入格式 仅一行,为两个正整数a和b(0≤a,b≤50000000). 输出格式 ...
- 【数论】【快速幂】CODEVS 2952 细胞分裂 2
裸快速幂取模,背诵模板用. #include<cstdio> using namespace std; typedef long long LL; LL n=,m,q; LL Quick_ ...
- 【数论】【快速幂】bzoj1008 [HNOI2008]越狱
根据 高中的数学知识 即可推出 ans=m^n-m*(m-1)^(n-1) .快速幂取模搞一下即可. #include<cstdio> using namespace std; typed ...
- ACM学习历程—HDU5667 Sequence(数论 && 矩阵乘法 && 快速幂)
http://acm.hdu.edu.cn/showproblem.php?pid=5667 这题的关键是处理指数,因为最后结果是a^t这种的,主要是如何计算t. 发现t是一个递推式,t(n) = c ...
随机推荐
- HDFS读写流程learning
有许多对流程进行描述的博客,但是感觉还是应当学习一遍代码,不然总感觉怪怪的,https://blog.csdn.net/popsuper1982/article/details/51615285,首先 ...
- 利用Object.defineProperty实现Vue数据双向绑定
body部分很简单,一个输入框和一个展示的div <div> <p>你好,<input id='nickName'></p> <div id=&q ...
- C++(三十二) — 常对象、常成员变量、常成员函数
常量:对于既需要共享.又需要防止改变的数据.在程序运行期间不可改变. const 修饰的是对象中的 this 指针.所以不能被修改. 1.常对象 数据成员值在对象的整个生存期内不能改变.在定义时必须初 ...
- 修改tomcat默认端口号8080
1.背景 在默认情况下,tomcat的端口是8080,使用了两个tomcat,那么就需要修改其中的一个的端口号才能使得两个同时工作. 2.方法 2.1改动一 那么,如何修改tomcat的端口号呢?首先 ...
- mysql中一个字段根据另一字段的值分割为不同列
1.数据结构如下: vehicleId mileage_type mileage 11AM6897 0 120 11AM6897 1 60 13AY9180 0 ...
- 几款必备LINUX的命令行神器
Dstat & sar iostat, vmstat, ifstat 三合一的工具,用来查看系统性能(我在<性能调优攻略>中提到过那三个xxstat工具). 官方网站:http:/ ...
- SHOW INNODB STATUS 探秘
[InnoDB系列] -- SHOW INNODB STATUS 探秘 SHOW INNODB STATUS 探秘 转载:http://imysql.com/2008_05_22_walk_throu ...
- vue请求本地json数据
1.下载vue-resource插件 cnpm install vue-resource 1.2全局引入vue-resource: 在main.js import VueResource from ' ...
- EPANET中的typedef使用
struct Floatlist /* Element of list of floats */{ double value; struct Floatlist *next;};typ ...
- 快速求排列组合 lucas定理
对于C(n, m) mod p.这里的n,m,p(p为素数)都很大的情况. 就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式递推了. 一般lucas定理的p ...