埃式篩法+快速冪運算
阿新 • • 發佈:2018-12-18
1.埃式篩法
應用:對很多整數進行素性測試-->要列舉n以內的素數
思路:2--n範圍內的所有整數,依次遍歷。遍歷過程中如果該數是素數則將其的倍數都劃去(可以想象他的倍數一定為非素數)。遍歷完成後。就可以列舉n以內的素數了。
模板:
void sieve(int n) { int t = 0; for(int i = 0;i<=n;i++) { is_prime[i] = true;//先將初始值均賦為true } for(int i = 2;i<=n;i++)//依次遍歷 { if(is_prime[i])//檢驗到目前為止其是不是素數 { t++;//是的 素數數目加一 for(int j = 2*i;j<=n;j+=i) { is_prime[j] = false;//其整數倍不是素數,置為false } } } printf("%d\n",t);//素數的數量 }
#include<stdio.h> #include<iostream> using namespace std; bool is_prime[1000100]; int main() { int n; while(scanf("%d",&n)!=EOF) { int t = 0; for(int i = 0;i<=n;i++) { is_prime[i] = true; } for(int i = 2;i<=n;i++) { if(is_prime[i]) { t++; for(int j = 2*i;j<=n;j+=i) { is_prime[j] = false; } } } printf("%d\n",t); } return 0; }
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> #include<string.h> #include<queue> using namespace std; const int maxn = 10010; bool book[maxn],prime[maxn]; int cnt[maxn],t[4],a,b,temp; void is_prime2()//判斷是否是負數 { int flag = 0; for(int i = 1000;i<=maxn;i++) { flag = 0; for(int j = 2;j*j<=i;j++) { if(i%j == 0) { flag = 1; prime[i] = false; } } if(!flag) prime[i] = true; } } int bfs(){ bool dis[maxn]; queue <int>q; int v,i,j,temp,vtemp,count[maxn],t[4]; memset(dis,false,sizeof(dis)); memset(count,0,sizeof(count)); q.push(a); dis[a]=true; while(!q.empty()){ v=q.front(); q.pop(); t[0]=v/1000; t[1]=v%1000/100; t[2]=v%100/10; t[3]=v%10; for(j=0;j<4;j++){ temp=t[j]; for(i=0;i<10;i++) if(i!=temp){ t[j]=i; vtemp=t[0]*1000+t[1]*100+t[2]*10+t[3]; if(!dis[vtemp] && prime[vtemp]){ count[vtemp]=count[v]+1; dis[vtemp]=true; q.push(vtemp); } if(vtemp==b) return count[vtemp]; } t[j]=temp; } if(v==b) return count[v]; } return -1; } int main() { int n; scanf("%d",&n); while(n--) { scanf("%d%d",&a,&b); is_prime2(); int key = bfs(); if(key == -1) { cout<<"Impossible"<<endl; } else cout<<key<<endl; } return 0; }
2.快速冪運算
反覆平方法
n為奇數:
偶數:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
bool is_prime[70000];
void prime()
{
for(int i = 2;i*i<70000;i++)
{
if(is_prime[i])
{
for(int j = 2*i;j<70000;j+=i)
{
is_prime[j] = false;
}
}
}
}
long long mod_pow(long long x,long long n,long long mod)
{
long long res = 1;
while(n>0)
{
if(n&1) //相當於n%2,1.起初奇數再乘以一個x 2.或者最後時res*x
{
res = res*x%mod;
}
x = x*x%mod; //不斷進行反覆平方
n>>=1;//相當於n/=2;
}
return res;
}
int main()
{
int flag;
long long n;
memset(is_prime,true,sizeof(is_prime));
prime();
while(scanf("%lld",&n)!=EOF&&n)
{
flag = 0;
if(is_prime[n])
{
printf("%lld is normal.\n",n);
continue;
}
for(int i = 2;i<n;i++)
{
long long c = mod_pow(i,n,n);
if(c!=i%n)
{
flag = 1;
break;
}
}
if(!flag)
{
printf("The number %lld is a Carmichael number.\n",n);
}
else
{
printf("%lld is normal.\n",n);
}
}
return 0;
}