codeforce 17D Notepad
这题实际求的是\(a^b\ mod\ n\),但是\(gcd(a,n)\)[下面记作(a,n)]不一定等于1.......
(a,n)等于1时直接费马小定理能推倒...
(a,n)不为1时,有如下事实(当然互素时显然成立):
\[a^{2\phi (n)}\ mod\ n = a^{\phi (n)}\ mod\ n\]
即
\[a^{\phi (n)}(a^{\phi(n)}-1)\ mod \ n =0\]
简单证明如下:
1.如果\(a^{\phi (n)}\ mod \ n =0\),等式显然成立.
2.否则,命题等价于
\[\frac{a^{\phi (n)} }{(a^{\phi (n)},n)} (a^{\phi (n)}-1) \ mod \ \frac{n}{(a^{\phi (n)} ,n)} = 0\]
即:
\[a^{\phi (n)}\ mod \ \frac{n}{(a^{\phi (n)} ,n)} = 1\]
到这里就能使用费马小定理了~
回到题目上:\(a^b\ mod\ n\)$实际上分两种情况:
1.\(b<\phi (n)\),此时直接算
2.else,\(a^b\ mod\ n=a^{b\ mod\ \phi (n)+\phi (n)}\ mod\ n\)
对任意(?)a,n成立
SPOJ3871 GCDEX
这题的描述对我这种语言能力残缺的人来说,复述起来太难:
现在证明,T(n)是一个积性函数
证明:
设 m , n 满足 (m,n)=1:
则:
由于(m,n)=1,故dn与dm互素,所有dn,dm的组合正好取遍mn的约数
到了这里,只需考虑n等于素数的幂时T(n)的值:
根据T(n)的定义,显然有:
有了这个性质,就有可以在O(n)时间内用这个 牛X的筛法 把表打出来,然后求和还是O(n),查询什么的显然O(1)咯lol...
代码:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #define FF(i,b) for(i=0;i<(b);i++) #define FOR(i,a,b) for(i=(a);i<=(b);i++) #define ZERO(x) do{memset(x,0,sizeof(x));}while(0) #define SWAP(a,b) do{int _tmp=a;a=b;b=_tmp;}while(0) #define INFI 2000000000 #define INFF 1e100 #define maxn 1000000 typedef long long LL; int p[maxn+1],ph[maxn+1],pk[maxn+1],T[maxn+1]; LL G[maxn+1]; void sevie() { memset(p,0,sizeof(p)); int i,j; p[0]=ph[0]=0;ph[1]=1;T[1]=1; for(i=2;i<=maxn;i++) { if(!p[i]){p[++p[0]]=i;ph[i]=i-1;pk[i]=i;T[i]=(i<<1)-1;} for(j=1;p[j]<=maxn/i;j++) { p[p[j]*i]=1; if(i%p[j]){ ph[i*p[j]]=ph[i]*p[j]; pk[i*p[j]]=p[j]; T[i*p[j]]=T[i]*T[p[j]]; } else{ ph[i*p[j]]=ph[i]*p[j]; pk[i*p[j]]=pk[i]*p[j]; if(i==pk[i])T[i*p[j]]=p[j]*T[i]+ph[i*p[j]]; else T[i*p[j]]=T[i/pk[i]]*T[pk[i]*p[j]]; break; } } } G[0]=0; for(i=1;i<=maxn;i++)G[i]=G[i-1]+T[i]-i; } int main ( int argc, char *argv[] ) { sevie(); int n; while(scanf("%d",&n)!=EOF) { if(!n)break; printf("%lld\n",G[n]); } return EXIT_SUCCESS; }
数论相关算法(未完)
辗转相除法最大公约数:
//要求a,b不同时为零 int gcd(int a,int b) { if(!b)return a; else return gcd(b,a%b); }
利用最大公约数求最小公倍数:
int lcm(int a,int b) { if(!(a*b))return 0; else return a*b/gcd(a,b); }
求:
int modExp(int a,int b,int n) { int t=1,y=(a%n+n)%n; while(b) { if(b%2==1)t=t*y%n; y=y*y%n; b/=2; } return t; }
扩展的Euclid算法:
//返回a,b的最大公约数d,并使ax+by=d int ExtEuclid(int a,int b,int *x,int *y) { int d,tmp; if(b==0) { *x=1; *y=0; return a; } d=ExtEuclid(b,a%b,x,y); tmp=*x; *x=*y; *y=tmp-a/b*(*x); return d; }
解线性同余方程:
//返回最小的x...通解是X=x(mod n/d) int modularLinerEquation(int a,int b,int n) { int x,y,d; d=ExtEuclid(a,n,&x,&y); if(b%d!=0)return -1; // no solution x=b/d*x; x=(x%(n/d)+(n/d))%(n/d); return x; }
用中国剩余定理解同余方程组:
//用中国剩余定理解线性同与方程组$a\equiv b_i(\mod m_i)$ int solModularEquations(int b[],int m[],int z) { int M=1,i,y,result=0; for(i=0;i<z;i++)M*=m[i]; for(i=0;i<z;i++) { y=modularLinerEquation(M/m[i],1,m[i]); result=(result+y*b[i]*M/m[i])%M; } return result; }
Miller-Rabin测试:
//Miller-Rabin素性测试 //令大奇数$n=2^lm+1$,其中l非负整数,m为正奇数. //若$b^m\equiv 1(\mod n)$或者$b^{2^jm}\equiv -1(\mod n)$ ,0<=j<=l-1 //则称n通过以b为基的miller-rabin测试 int passMillerRabinTest(int n) { int l,m; m=n-1; l=0; while(m%2==0) { l++; m/=2; } b=rand()%(n-1)+1; if(modExp(b,m,n)==1)return 1; int i,k; k=m; for(i=0;i<l;i++) { if(modExp(b,k,n)==n-1)return 1; k*=2; } return 0; }