你好 数论(未完待续)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你好 数论(未完待续)相关的知识,希望对你有一定的参考价值。
据说每年noip都会考数论的题?!
蒟蒻表示智商不够,被数论完虐。。。。。
所以我就只能在这里整理整理各种数论的板子了。。。。
一.素数
http://www.cnblogs.com/mycapple/archive/2012/08/07/2626898.html
1.欧拉筛(线性筛)
int Euler_sieve() { memset(not_prime,0,sizeof(not_prime)); for(int i=2;i<=n;i++) { if(!not_prime[i]) prime[++tot]=i; for(int j=1;j<=tot;j++) { if(i*prime[j]>N) break; not_prime[i*prime[j]]=1; if(i%prime[j]==0) break; } } }//若 not_prime[i]为0则为素数 注意:not_prime[1]=1;
2.简单的素数判定
int pd(int x) { for(int i=2;i*i<=x;i++) if(x%i==0) return false; return true; }
二.欧几里得+扩展欧几里得
讲解:http://blog.csdn.net/zhjchengfeng5/article/details/7786595
1.欧几里得
int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); }
2.扩展欧几里得
①求乘法逆元
int exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1,y=0; return a; } int r=exgcd(b,a%b,x,y),tmp; tmp=x,x=y,y=tmp-a/b*y; return r; } int main() { a=read(),b=read(); gcd=exgcd(a,b,x,y); if(gcd!=1) printf("不存在"); else {while(x<=0) x+=b/gcd; printf("%d",x);} }
②小扩展:除法取模运算
(a/b)mod p=?
定义 c为b在mod p意义下的逆元
=a*c mod p = (a mod p * c mod p)mod p
③求解同余方程
拓展欧得用于求解形如 ax + by = gcd(a,b) 的不定方程的一组解. 该算法保证求出的 x,y 满?足|x| + |y| 最小
ax三c(mod b)——> ax+by=c——>我们可以知道c=gcd*c/gcd,那么原式又可以变成ax/(c/gcd)+by/(c/gcd)=c/(c/gcd)我们令x1=x/(c/gcd),y1=y/(c/gcd),——>x=x1*(c/gcd) 那么原式又可以变成ax1+by1=gcd; 最终x=x1*c/gcd
三.欧拉函数
http://blog.csdn.net/sentimental_dog/article/details/52002608
求1~n中有几个数与n互质
int get_phi(int x) { int sum=x; if(x%2==0) { while(x%2==0) x/=2; sum/=2; } for(int i=3;i*i<=x;i+=2) { if(x%i==0) { while(x%i==0) x/=i; sum=sum/i*(i-1); } } if(x>1) sum=sum/x*(x-1); return sum; }
小规律:(需要用欧拉函数的情况)
1.对于方阵的问题,我们如果要求一个人站在一个位置时事业所能看到的人的个数可以将其转换成欧拉函数。我们将其所在的位置设为(0,0),那么如果存在一个点(x,y),且有gcd(x,y)=k(k!=1),那么点(x/k,y/k)一定会将(x,y)挡住。而如果k=1,那么点(x,y)就一定会被看到。 这样就会想到这不是欧几里得吗??怎么跟欧拉函数扯上关系了??? 某位大佬跟我说你用欧几里得吧,T死你。我们把这个题的式子列出来
n n n i
∑ ∑ [gcd(i,j) = 1] + 2 将以上式子拆成两半等于 2(∑ ∑ [gcd(i,j)=1]))+1
i=1 j=1 i i=1 j=1
我们又可以知道 φ(i) =∑ j=1 [gcd(i,j) = 1] 所以就真的变成了裸地欧拉函数
2.求1~n中与n的最大公约数大于m的数的个数
我们考虑gcd这样一个性质gcd(x,y)=m则gcd(x/m,y/m)=1;我们就可以轻易的发现在这个地方的x/m不就是我们要求的第一个式子中的x吗??这样我们就只需要统计这样的x/m的个数不就好了吗?!发现这样会T的很惨。这样我们来找一个不T的方法:一个数的最大公约数是不是一定是她的因子。求每一个数的公约数的因子的时候是不是可以直接枚举到根n??对于我们处理出来的因子是不是有两个来源,一个是本身i,另一个是n/i??
这样我们就可以分两种情况来判断,一是i>m,另一种是n/i大于m,这样我们再求n/i的欧拉函数与n/n/i即i的欧拉函数就好了。
欧拉函数+处理
for(int i=1;i*i<=n;i++) { if(n%i==0) { if(i>=m&&i*i!=n) ans+=get_phi(n/i); if(n/i>=m) ans+=get_phi(i); } }
四.卡特兰数
http://www.cnblogs.com/z360/p/6561567.html
卡特兰数的应用:
2.在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。
3.矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?
4.在一个圆上,有2*K个不同的结点,我们以这些点为端点,连K条线段,使得每个结点都恰好用一次。在满足这些线段将圆分成最少部分的前提下,请计算有多少种连线的方法
5.出栈次数
核心代码:
h[0]=1,h[1]=1; for(int i=2;i<=n;i++) for(int j=1;j<=i;j++) h[i]=h[j-1]*h[i-j]+h[i]; ans=h[n];
高精卡特兰数
#define N 110 int n,len,ans,sum,tmp,a[N][N],b[N]; int catelan() { len=1; a[1][0]=b[1]=1; for(int i=2;i<110;i++) { for(int j=0;j<len;j++) a[i][j]=a[i-1][j]*(4*i-2); sum=0; for(int j=0;j<len;j++) { tmp=sum+a[i][j]; a[i][j]=tmp%10; sum=tmp/10; } while(sum) { a[i][len++]=sum%10; sum/=10; } for(int j=len-1;j>=0;j--) { tmp=sum*10+a[i][j]; a[i][j]=tmp/(i+1); sum=tmp%(i+1); } while(!a[i][len-1]) len--; b[i]=len; } }
以上是关于你好 数论(未完待续)的主要内容,如果未能解决你的问题,请参考以下文章