基本数论(从整除入门到欧拉弃坑到中国剩余BSGS跑路)
来源:互联网 发布:专业英语翻译软件 编辑:程序博客网 时间:2024/06/05 04:40
毕业了一点都不开心。
ps:本来就是自己看看所以随便写点什么都可以
整除
首先,我们需要一些看起来很有用然而除了装逼没有任何价值的定理:
1.如果
a∣b 且b∣c ,那么a∣c (等同放p)
2.a∣b 等价于对任意整数x 和y ,有a∣(b∗x+c∗y)
3.设m≠0 ,那么a∣b 等价于(m∗a)∣(m∗b) (此条等同于放p)
4.设整数x和y满足下式:a∗x+b∗y=1 ,且a∣n 、b∣n ,那么(a∗b)∣n
5.若b=q∗c ,那么d∣b 的充要条件是d∣c
剩下的空着吧
同余
首先,我们要知道:如果a与b关于模m同余,记为:
那么,对于整数a,b,c和自然数m,n
1.自反性:
a≡a(mod m)
2.对称性:若a≡b(mod m) ,则b≡a(mod m)
3.传递性:若a≡b(mod m) ,b≡c(mod m) ,则a≡c(mod m)
4.同加性:若a≡b(mod m) ,则a+c≡b+c(mod m)
5.同乘性:若a≡b(mod m) ,则a∗c≡b∗c(mod m)
若a≡b(mod m) ,c≡d(mod m) ,则a∗c≡b∗d(mod m)
6.同幂性:若a≡b(mod m) ,则an≡bn(mod m)
7.推论1:a∗b mod k=(a mod k)∗(b mod k)mod k
8.推论2:若a mod p=x ,a mod q=x ,p、q互质,则a mod p∗q=x
辗转相除法
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
二进制超级卡常版辗转相除法
template<class T> T gcd(T a,T b) { if(!a|!b) return a|b; int i,j; for(i=0;!(x&1);++i) x>>=1; for(j=0;!(y&1);++j) y>>=1; for(i=j<i?j:i;;) { if(x<y) x^=y,y^=x,x^=y; if(!(x-=y)) return y<<i; for(;!(x&1);) x>>=1; }}
脱非扩欧
相信大家都会不定方程的分解因数法,那么在这里就可以简单带过:
求一对x,y,使得根据某些数论知识,这个方程显然有解
另某一组特殊解为x0,y0,那么就可以得到通项公式:
由于gcd的结束条件是a=gcd,b=0,此时有解x1=1,y1=0,根据
那么:x1=y1,y1=x1-a/b*y1
template <class T> T e_gcd(T a,T b) { if(!b) {x=1,y=0;return a;} int temp=x; gcd=e_gcd(b,a%b); x=y,y=temp-a/b*y; return gcd;}
然后,不定方程
至于求逆元,我们可以当成不定方程
ZOJ3609,代码长这样:
#include<cstring>#include<cstdio>using namespace std;typedef long long LL;template <class T> void read(T &x) { x=0;LL f=1;char ch=getchar(); for(;ch<'0'||ch>'9';) {if(ch=='-') f=-1;ch=getchar();} for(;ch>='0'&&ch<='9';) x=x*10+ch-'0',ch=getchar();x*=f;}template <class T> void write(T x) { LL num=0;char ch[20]; if(x<0) putchar('-'),x=-x; do ch[++num]=x%10+'0',x/=10; while(x); for(;num;) putchar(ch[num--]);putchar('\n');}LL e_gcd(LL a,LL b,LL &x,LL &y) { if(!b) {x=1,y=0;return a;} LL temp,gcd; gcd=e_gcd(b,a%b,x,y),temp=x; x=y,y=temp-a/b*y; return gcd;}LL cal(LL a,LL b,LL c) { LL ans,gcd,x,y; gcd=e_gcd(a,b,x,y); if(c%gcd!=0) return -1; x*=c/gcd,b/=gcd; if(b<0) b=-b; ans=x%b; if(ans<=0) ans+=b; return ans;}int main() { LL a,b,ans,test; for(read(test);test--;) { read(a),read(b),ans=cal(a,b,1); if(ans!=-1) write(ans);else puts("Not Exist"); } return 0;}
POJ1061 裸裸的
ZOJ3593 画出两条直线yy一下
HDU1576 求逆元裸题,然而可以暴力
HDU2669 裸题(吐嘈一下比赛名字)
(天哪一个上午+两个小时就干了这么一点点东西简直了……)
求解线性同余方程
求解
参照上方不定方程求解。
由于只需要一个解,所以这里可以简单一点。
设间隔为dx,简单推导:
相减:
好咯,那么
所以
瞎搞瞎搞。
中国剩余定理
孙子算经:
之前一直以为很高深啊很高深,老祖宗们真是太聪明了……
不过发现原来就是套,不过祖宗们套的方法高深一些,其实与小学生们的解法是有一定相似之处的…..
孙子问题解法的本质是从5和7的公倍数中找一个除以3余2的数n1,从3和7的公倍数中找一个除以5余3的数n2,从3和5的公倍数中找一个除以7余2的数n3,再将三个数相加得到解。在求n1,n2,n3时又用了一个小技巧
最后,我们还要清楚一点,n1+n2+n3只是问题的一个解,并不是最小的解。如何得到最小解?因为显然有
POJ1006 裸裸裸
中国剩余定理:
自然数
m1,m2......mk 两两互素,求最小正整数解:
⎧⎩⎨⎪⎪⎪⎪x≡c1(mod m1)x≡c2(mod m2)x≡c3(mod m3)...x≡ck(mod mk)
那么就有:
令M=m1∗m2∗m3∗......∗mk ,inv(Mmi,mi) 表示逆元
则x=(∑ki=1(ci∗Mmi∗inv(Mmi,mi)))mod M
证明通俗易懂就不说了还不是懒
codevs3990
#include<cstring>#include<cstdio>using namespace std;typedef long long LL;LL m[15],c[15],ans,Min,M=1;LL exgcd(LL a,LL b,LL &x,LL &y) { if(!b) x=1,y=0; else exgcd(b,a%b,y,x),y-=a/b*x;}int main() { LL a,b,l,r,x,y,N=0;int i,n; for(scanf("%d%lld%lld",&n,&l,&r),i=1;i<=n;i++) scanf("%lld%lld",m+i,c+i),M*=m[i]; for(i=1;i<=n;i++) { a=M/m[i],b=m[i],exgcd(a,b,x,y); x=(x%b+b)%b; if(!x) x+=b; N+=c[i]*a*x; } N%=M; if(!N) N+=M; if(r>=N) ans=(r-N)/M+1; if(l>=N) ans=ans-((l-N)/M+1); if((l-N)%M==0) ++ans; if(ans) { if(l<=N) Min=N; else Min=N+((l-N)/M+1)*M; } printf("%lld\n%lld\n",ans,Min); return 0;}
扩展
然后还有一个扩展(不互素怎么办捏?):
puts("先骗偏访问量然后过来填坑");
素数
素数相关定理
1.唯一分解定理(p话)
2.威尔逊定理
若p为素数,则
(p−1)!≡−1(mod p)
若对某一正整数p,有(p−1)!≡−1(mod p)
3.费马定理
若p为素数,a为正整数,且a和p互质,则:
ap−1≡1(mod p)
小定理:
ap≡a(mod p)
欧拉函数
为积性函数,即当
1.
void euler(int n) { int m=(int)sqrt(n+0.5); int ans=n; for(int i=2;i<=m;i++) if(!(n%i)) for(ans=ans/i*(i-1);!(n%i);) n/=i; if(n>1) ans=ans/n*(n-1);}
2.
1.
2.
证明:
令n==pk ,小于 n 的正整数共有pk−1 个,其中与 p 不互素的个数共pk−1−1 个,它们是1∗p,2∗p,3∗p...(pk−1−1)∗p
所以phi(pk)==(pk−1)−(pk−1−1)==pk−pk−1==(p−1)∗pk−1 。
3.如果
4.如果
int prime[MAXN],check[MAXL],phi[MAXL];int main() { int i,j,tot=0; phi[1]=1; memset(check,0,sizeof(check)); for(i=2;i<MAXL;++i) { if(!check[i]) prime[tot++]=i,phi[i]=i-1; for(j=0;j<tot&&i*prime[j]<=MAXL;++j) { check[i*prime[j]]=1; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } }}
一道必刷题:poj2480
求
公式为:
由于积性函数的和必然是积性函数,所以此题可以利用积性做
Baby Steps Giant Steps及其扩展
又名拔山盖世算法、大步小步算法、北上广深算法、百事公司算法。
用来解决这么一个式子
先令
x=i∗m−j ,其中m=⌈C‾‾√⌉ 。
这样原式就变为Ai∗m−j≡B(mod C) ,
再变为Aj×B≡Am∗i(mod C) 。
枚举j(范围0-m)(显然),将Aj×B 存入hash表
枚举i(范围1-m),从hash表中寻找第一个满足Aj×B≡Am∗i(modC) 。
此时x=i∗m−j 即为所求。
在网上大多用的是x=i∗m+j ,也可以做,只是会牵扯的求逆元,所以比较麻烦。使x=i∗m−j 就可以避免这个问题了。
有一个公式ak mod p−1≡ak(mod p) 这个公式的推导需要用到费马小定理
k mod p−1 可以看做k−m(p−1) ,原式可化成ak/(ap−1)m≡ak(mod p)
根据费马小定理ap−1≡1(mod p) 其中p为质数 ,a,p 互质,可得ak/1m≡ak(mod p)ak≡ak(mod p) 得证。
代码什么的,只要会打快速幂,剩下的就是暴力枚举了。
模板题poj2417(其实大佬们敲不敲随便的啦)
扩展:与中国剩余定理一样的方式
如果凉拌,炒鸡蛋
令
d=gcd(A,C) ,如果d∤B 显然只有x=0,B=1 这一种解
如果d∣B :
首先,如果C与A互质,那么直接BSGS
如果不互质怎么办?
那么Ax−1∗Ad≡Bd (mod Cd)
如果现在互素了,开始求x-1
如果还不互素,就一直求到d2......dk 。
现在A 与C∏ki=1di 互素
Ax−k∗Ak∏ki=1di≡B∏ki=1di (mod C∏ki=1di)
如果∏ki=1di∣B ,只有x=0 这唯一解
如果∏ki=1di∤B ,暴力枚举x∈[0,k) ,找到了就找到了,对于x>k :
Ax−k≡B∗A−k(mod C∏ki=1di)
令x′=x−k ,B′=B∗A−k ,C′=C∏ki=1di ,
Ax′≡B′ (mod C′)
然后BSGS来一遍求出x′ ,正解x就是x′+k
卧曹怎么看着这么像暴力啊
没错好像BSGS就是暴力啊
poj3243
- 基本数论(从整除入门到欧拉弃坑到中国剩余BSGS跑路)
- [数论][二次剩余][BSGS] CodeChef FN
- 【数论】hdu5768 Lucky7(中国剩余定理)
- 数论-中国剩余定理
- 数论/中国剩余定理
- 【数论】中国剩余定理
- 中国剩余定理【数论】
- 数论--中国剩余定理
- bsgs(数论)
- [数论 && 二次剩余 && BSGS] Codechef FN. FIBNACCI NUMBER
- [数论]中国剩余定理 CRT
- (ACM数论)中国剩余定理(孙子定理)
- HDU 1573 X问题 数论-(中国剩余定理)
- POJ 1006 Biorhythms (数论-中国剩余定理)
- 数论E - Biorhythms(中国剩余定理,一水)
- 51nod1079---中国剩余定理(51nod基础:数论)
- 基础数论算法(4) 中国剩余定理
- 中国剩余定理入门
- byte型&十六进制
- 【IIS】HTTP 错误 500.19
- 云锁机制的网页爬取
- 使用PLSQL完成功能
- 从基础开始学java
- 基本数论(从整除入门到欧拉弃坑到中国剩余BSGS跑路)
- Time to Buy and Sell Stock系列
- swift3 as?和as!
- 判断自己的网络是不是公网IP
- C++内存处理
- JSTL标签
- 初接触SSM(Spring+Spring MVC+Mybatis)
- Java中的设计模式
- [bzoj4034][HAOI2015]树上操作