回顧:
數論四大定理
威爾遜定理若p爲質數,則p可整除(p-1)!+1。
若n,a爲正整數,且n,a互素,(a,n) = 1,則
a^φ(n) ≡ 1 (mod n)
公元前後的《孫子算經》中有“物不知數”問題:“今有物不知其數,三三數之餘二 ,五五數之餘三 ,七七數之餘二,問物幾何?”答爲“23”。
明朝程大位用歌謠給出了該題的解法:“三人同行七十稀,五樹梅花廿一枝,七子團圓月正半,除百零五便得知。”
以現代的說法,是找出三個關鍵數70,21,15。解法的意思就是用70乘3除所得的餘數,21乘5除所得的餘數,15乘7除所得的餘數,然後總加起來,除以105的餘數就是答案。
假如p是質數,且(a,p)=1,那麼 a^(p-1) ≡1(mod p)。
假如p是質數,且a,p互質,那麼 a的(p-1)次方除以p的餘數恆等於1。
1.威爾遜定理 HDU 2973 YAPTCHA
這題就是威爾遜定理的一個簡單應用,由於向下取整的存在,式子的值就‘0’或‘1’。
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
bool f(int x)
{
int i,n=int(sqrt(double(x)));
if(x==2||x==3)
{
return true;
}
for(i=2;i<=n;++i)
{
if(x%i==0)
{
return false;
}
}
return true;
}
int a[1000001];
void g()
{
int i;
a[1]=0;
for(i=2;i<=1000000;++i)
{
if(f(3*i+7)==true)//判斷是否爲素數,而確定前式是否爲整除式
{
a[i]=a[i-1]+1;
}
else
{
a[i]=a[i-1];
}
}
}
int main()
{
int t,n,i;
g();
RD(t);
while(t--)
{
RD(n);
OT(a[n]);
printf("\n");
}
return 0;
}
2.歐拉定理 HDU 1395 2^x mod n = 1
歐拉定理的直接應用,求出n以內與n互質的數量
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
int main()
{
int n,sum,i;
while(scanf("%d",&n)!=EOF)
{
if(n==1||n%2==0)
{
printf("2^? mod %d = 1\n",n);
}
else
{
sum=1;
for(i=1;i<5001;++i)//求互質數
{
sum*=2;
sum%=n;
if(sum==1)
{
break;
}
}
printf("2^%d mod %d = 1\n",i,n);
}
}
return 0;
}
孫子定理的一般應用,由於存在不可能的情況,所以不建議使用直接暴搞,應使用擴展歐幾里得公式,求出初等公式,在一步步求解。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
int ext_gcd(int a,int b,int& x,int& y)//擴展歐幾里德
{
int t,ret;
if (!b)
{
x=1,y=0;
return a;
}
ret=ext_gcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return ret;
}
int main()
{
int i,t,n,cas=0,f,m1,m2,a1,a2,z,x,y,j,m[11],a[11];
RD(t);
while(t--)
{
cas++;
RD(n);
for(i=0; i<n; i++)
{
RD(m[i]);
}
for(i=0; i<n; i++)
{
RD(a[i]);
}
f=0;
m1=m[0];
a1=a[0];
for(i=1; i<n; i++)//求遞推式
{
m2=m[i];
a2=a[i];
z=ext_gcd(m1,m2,x,y);
if((a2-a1)%z)
{
f=1;
break;
}
j=m2/z;
x=(x*(a2-a1))/z;
x=(x%j+j)%j;
a1=m1*x+a1;
m1=(m1*m2)/z;
a1=(a1%m1+m1)%m1;
}
if(f==1)
{
a1=-1;
}
if(a1==0&&n>1)
{
a1=m1;
}
if(a1==0&&n==1)
{
a1=m[0];
}
printf("Case %d: %d\n",cas,a1);
}
return 0;
}
一道費馬小定理的變型題,要求n以內包括n的數相乘組成一個最大的完全平方數,需要先通過唯一分解定理將N!(必爲最大)分解爲質因數的相應次冪相乘,由於要得到的是完全平方數,所以需要除去次冪數爲奇數的質因數(除1次)。最後可以轉化爲MAX(n)=(n!*b^(mod-2))%mod。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
#define M 10000001
using namespace std;
__int64 b[M];
int a[M],m;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
void f()//求N!,求質因數表
{
int i,j;
b[0]=1;
for(i=1;i<M;++i)
{
b[i]=b[i-1]*i%N;
}
int x=sqrt(M*1.0);
for(i=2;i<=x;++i)
{
if(!a[i])
{
for(j=i*i;j<M;j+=i)
{
a[j]=1;
}
}
}
for(i=2;i<M;++i)
{
if(!a[i])
{
a[m++]=i;
}
}
}
__int64 p(__int64 x,__int64 y)//快速冪取模
{
__int64 res=1;
while(y>0)
{
if(y%2==1)
{
res=(res*x)%N;
}
x=(x*x)%N;
y/=2;
}
return res;
}
int main()
{
f();
int n,i,tmp,tsp;
__int64 ans,sum;
while(scanf("%d",&n))
{
if(n==0)
{
break;
}
sum=1;
for(i=0;i<m&&a[i]<=n;++i)
{
tmp=n;
tsp=0;
while(tmp)
{
tsp+=(tmp/=a[i]);
}
if(tsp%2==1)
{
sum=sum*a[i]%N;
}
}
ans=b[n]*p(sum,N-2)%N;//費馬小定理
printf("%I64d\n",ans);
}
return 0;
}
陸續還有總結,敬請期待~