数论篇 卷一 未知的世界
我爱学习,学习使我快乐。
然而数学使我吐血。
本篇将会粗略整理一些基础数论知识,并汇总博主做过的一些数学知识要求高的题目。
但到目前为止,博主什么都不会,所以这里基本什么也没有。
一、欧几里得算法
也就是俗称的辗转相除法。
甩个代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 int x,y; 8 int gcd(int x,int y){ 9 return y?gcd(y,x%y):x; 10 } 11 int main(){ 12 scanf("%d%d",&x,&y); 13 if(x<y)swap(x,y); 14 printf("%d",gcd(x,y)); 15 return 0; 16 }
TYVJ3966有道裸题。刷题记录喜+1
TYVJ1727需要来一波理论分析。道理虽然懂了,但是具体实现需要一大堆高精写上去,我选择弃坑
二、扩展欧几里得算法
1 int exgcd(int a,int b,int &x,int &y){ 2 if(b==0){ 3 x=1;y=0; 4 return a; 5 } 6 int res=exgcd(a,a%b,y,x); 7 y-=a/b*x; 8 return res; 9 }
1 void exgcd(int a,int b,int &x,int &y){ 2 if(b==0){ 3 x=1;y=0; 4 return; 5 } 6 exgcd(b,a%b,x,y); 7 int t=x;x=y;y=t-a/b*y; 8 }
三、线性筛
这篇讲得特别好:
http://blog.csdn.net/dinosoft/article/details/5829550
四、欧拉函数
欧拉函数是小于等于n的数中与n互质的数的数目。
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int mxn=10000; 9 int phi[mxn];//欧拉函数数组 10 int mark[mxn];//[i]的最小质因数 11 int pr[mxn],cnt=0;//质数数组 12 void euler(){ 13 phi[1]=1; 14 int i,j; 15 for(i=2;i<mxn;i++){ 16 if(!mark[i])pr[++cnt]=mark[i]=i,phi[i]=i-1;//素数性质,f(i)=i-1 17 for(j=1;j<=cnt && pr[j]*i<mxn;j++){ 18 mark[i*pr[j]]=pr[j]; 19 if(mark[i]==pr[j]){ 20 phi[i*pr[j]]=pr[j]*phi[i]; 21 ///*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/ 22 break; 23 } 24 else phi[i*pr[j]]=phi[i]*(pr[j]-1); 25 //积性函数性质,f(i*k)=f(i)*f(k) 26 } 27 } 28 return; 29 } 30 int main(){ 31 euler(); 32 int n; 33 scanf("%d",&n); 34 printf("%d\n",phi[n]); 35 return 0; 36 }
也可以直接按照上面的通式计算:
1 long long phi(long long x){ 2 long long a=x; 3 for(long long i=2;i<=m;i++){ 4 if(x%i==0){//找到因数 5 a=a/i*(i-1);//基本计算公式 a*=((i-1)/i) 6 while(x%i==0)x/=i;//除去所有相同因数 7 } 8 } 9 if(x>1)a=a/x*(x-1);//处理最后一个大因数 10 return a; 11 }
一道裸题:Bzoj2705
题解链接附:http://www.cnblogs.com/SilverNebula/p/5656723.html
五、中国剩余定理
中国剩余定理用来解决如下的同余方程的解
$ x \equiv b_1 (\bmod m_1)$
$ x \equiv b_2 (\bmod m_2) $
$ x \equiv b_3 (\bmod m_3) $
...
若$m_1 ,m_2 ,m_3 , ...$ 互素,则方程有整数解。
设$M = m_1 * m_2 *m_3 ...$ ,在模M意义下同余方程组有唯一整数解。
则$ ans=\sum_{i=1}^{k} b_i * \frac{M}{m_i}*inv(\frac {M}{m_i},m_i) \bmod M $
我们知道所有的m两两互质,所以 $\frac{M}{m_i}$ 是除$ m_i $以外所有的m的最小公倍数。
设有一个 $ c_i $ 满足
$ c_i \equiv 0 (\bmod \frac{M}{m_i})$ ,
$ c_i \equiv 1 (\bmod m_i)$
显然有
$ b_i *c_i \equiv 0 (\bmod \frac{M}{m_i})$
$ b_i *c_i \equiv b_i (\bmod m_i)$
现在来求c:
$ \frac{M}{m_i} * x = c_i=m_i*y+1$
也就是
$ \frac{M}{m_i} * x - m_i*y =1$
这个东西可以用扩展欧几里得解出来。
解该方程也可以看作是求 $\frac{M}{m_i}$ 在模 $m_i$ 意义下的逆元。
我们把解出的这个x乘上 \frac{M}{m_i},再乘上$ b_i $ ,加到ans里,现在ans满足了当前这个同余方程,并且其他同余方程的余数没有受到影响。
如此处理每一个同余方程,就得到了方程组的解。
1 LL exgcd(LL a,LL b,LL &x,LL &y){ 2 if(!b){ 3 x=1;y=0; 4 return a; 5 } 6 LL res=exgcd(b,a%b,x,y); 7 LL t=x;x=y;y=t-a/b*x; 8 return res; 9 } 10 LL CRT(){ 11 LL M=1; 12 LL res=0; 13 int i,j;LL x,y; 14 for(i=1;i<=n;i++){M*=a[i];} 15 for(i=1;i<=n;i++){ 16 LL tmp=M/a[i]; 17 exgcd(tmp,a[i],x,y); 18 res=(res+tmp*x*b[i])%M; 19 } 20 res=(res+M)%M; 21 return res; 22 }
六、扩展中国剩余定理
用来解决模数并不互质的同余方程组
其实没有这个定理(大概),所谓“扩展”就是用扩展欧几里得把模数不互质的同余方程组化成模数互质的同余方程组,再用中国剩余定理求解。
例如
$ x \equiv c_1 (\bmod m_1) $
$ x \equiv c_2 (\bmod m_2) $
可得
$m_1* k_1+c_1 = m_2 * k_2 + c_2$
$m_1 * k_1 - m_2 * k_2 = c_2-c_1$
根据裴蜀定理(http://www.cnblogs.com/SilverNebula/p/6807569.html)
该式有解的条件是$gcd(m_1,m_2)|(c_2-c_1)$
记$ GCD=gcd(m_1,m_2) $
此时可以将原式两边同除以GCD,得到:
$\frac {m_1}{GCD} *k_1= \frac{c_2-c_1}{GCD}+ \frac{m_2}{GCD} * k_2$
$ k_1 * \frac{m_1}{GCD} \equiv \frac{c_2-c_1}{GCD} (\bmod \frac{m_2}{GCD})$
$ k_1 = inv(\frac{m_1}{GCD},\frac{m_2}{GCD}) * \frac{c_2-c_1}{GCD}+y*\frac{m_2}{GCD}$
将$k_1$代回刚开始的同余方程,得到
$x=m_1 * \frac{c_2-c_1}{GCD} *inv(\frac{m_1}{GCD} , \frac{m_2}{GCD}) +c_1 + y* (m1*\frac{m_2}{GCD})$
$x \equiv m_1 * \frac{c_2-c_1}{GCD} *inv(\frac{m_1}{GCD} , \frac{m_2}{GCD}) + c_1 (\bmod \frac{m_1*m_2}{GCD})$
设$ C= m_1 * \frac{c_2-c_1}{GCD} *inv(\frac{m_1}{GCD} , \frac{m_2}{GCD}) + c_1$
$ M= \frac{m_1*m_2}{GCD}$
于是就把两个方程合并成了$x \equiv C (\bmod M)$
把所有方程像这样依次合并起来,最后得到的C就是x的解
1 LL m1=m[1],c1=c[1]; 2 for(i=2;i<=k;i++){ 3 LL m2=m[i],c2=c[i]; 4 LL tmp=gcd(m1,m2); 5 if((c2-c1)%tmp){printf("NO\n");return 0;}//无解 6 LL m3=m1/tmp*m2,c3=inv(m1/tmp,m2/tmp); 7 c3=ksmul(c3,(c2-c1)/tmp,m2/tmp); 8 c3=ksmul(c3,m1,m3); 9 c3=((c3+c1)%m3+m3)%m3; 10 m1=m3;c1=c3; 11 }
七、Lucas定理
求解模意义下的组合数问题:
$C_{n}^{m} = \prod_{i=1}^{k} C_{n_i}^{m_i} (\bmod p)$ 其中p是质数
$n=n_k * p^k + n_{k-1} + p^{k-1} + n_{k-2} * p^{k-2} + ... +n_1 * p + n_0$
$m=m_k * p^k + m_{k-1} + p^{k-1} + m_{k-2} * p^{k-2} + ... +m_1 * p + m_0$
也就是把n和m进行p进制拆分,然后分别计算。
傻傻不会证明
1 int pw[mxn],inv[mxn]; 2 void init(){ 3 pw[1]=1;inv[1]=1; 4 pw[0]=1;inv[0]=1; 5 for(int i=2;i<mod;i++){ 6 pw[i]=pw[i-1]*i%mod; 7 inv[i]=(-(mod/i)*inv[mod%i]%mod+mod)%mod; 8 } 9 return; 10 } 11 int calc(int n,int m){ 12 if(n<m)return 0; 13 return pw[n]*inv[pw[m]]%mod*inv[pw[n-m]]%mod; 14 } 15 int lucas(int n,int m){ 16 if(!m)return 1; 17 return calc(n%mod,m%mod)*lucas(n/mod,m/mod)%mod; 18 }
八、扩展Lucas定理
参考了这里http://blog.csdn.net/clove_unique/article/details/54571216
求$ C_n^m (\bmod P)$的值,P不一定是质数
把P分解质因数, $ P=p_1^{k_1} * p_2^{k_2} *p_3^{k_3} *...$
分别在模$ p_i^{k_i} $的意义下求出解,然后列出同余方程:
$x \equiv c_1 (\bmod p_1^{k_1})$
$x \equiv c_2 (\bmod p_2^{k_2})$
$x \equiv c_3 (\bmod p_3^{k_3})$
$ ... $
显然这些$ p_i^{k_i} $ 两两互质,可以用中国剩余定理合并
那么$ C_n^m (\bmod p_i^{k_i})$ 怎么求?
$ C_n^m (\bmod p_i^{k_i})$
可以用组合数公式 $ C_n^m=\frac{n!}{m!(n-m)!} $计算,此时我们需要快速求出 $n! \bmod p_i^{k_i} $
举个栗子:
$p=3 $, $k=2 $, $ p_i^{k_i}$=9 , $ n=19 $
$n!= 1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19$
$n!= 1*2*4*5*7*8*10*11*13*14*16*17*19*3*6*9*12*15*18$
$n!= 1*2*4*5*7*8*10*11*13*14*16*17*19*3^6*1*2*3*4*5*6$
$n!= [1*2*4*5*7*8]*[(1+9)*(2+9)*(4+9)*(5+9)*(7+9)*(8+9)]*[19]*[3^6]*[1*2*3*4*5*6]$
第一部分可以通过求模p意义下的阶乘得到;
第二部分展开以后约掉带$p^k$的项就和第一部分一样;
第三部分是序列长度除以$p^k$多出来的部分,不超过$p^k$个,可以直接求;
第四部分是$p^{\lfloor n/p \rfloor}$;第五部分是连续的阶乘,可以递归计算。
注意到第四部分可能使得$ m! $ 和 $ (n-m)!$不与$p^k$互质,导致无法求逆。解决办法是不算它们,改算$ C_n^m $里共有多少个因数p,算完其他部分以后再把这些p乘进去
计算n!中质因子p的个数x的公式为$x=\lfloor \frac{n}{p} \rfloor+\lfloor \frac{n}{p^2} \rfloor +\lfloor \frac{n}{p^3} \rfloor + ... $,可以递归计算。