标签:质数 mat 范围 正文 区间 can art png htm
以下正文
有二进制非递归和基本递归两种做法,代码呈现的是二进制非递归
#include <cstdio>
#include <cmath>
using namespace std;
int main(){
long long ans=1,i,j,k,m,n,b,p;
scanf("%lld%lld%lld",&b,&m,&p);
printf("%lld^%lld mod %lld=",b,m,p);
while(m>0){
if(m%2==1)
ans=ans*b%p;
b=b*b%p;
m=m>>1;
}
printf("%lld",ans%p);
return 0;
}
计算\((a\times b)\%p\)怎么办?\(((a%p)\times (b%p))\%p\)还是会溢出。
下面用到一种思想,神奇与上面的快速幂有异曲同工之妙,把\(b\)看成二进制表示。
举个栗子:\(4\times 13\%p\),看成是\(4\times 1101(2)\%p\),其实表示的是\(4\times (1\times 2^3+1\times 2^2+0\times 2^1+1\times 2^0)\%p\),那么我们在计算的时候就把b看成二进制,如果二进制最后一位是1,就说明这一位应该乘\(a\)取余,为零说明这一位不用乘\(a\),从低位开始不断将\(b\)的二进制式右移,同时将\(a\)乘以2,等同于把基数平方,原因见上式。
#include <iostream>
using namespace std;
long long q_mod(long long a,long long n,long long p)
{
a = a%p;
//首先降a的规模
long long sum = 1;//记录结果
while(n)
{
if(n&1)
{
sum = (sum*a)%p;//n为奇数时单独拿出来乘
}
a = (a*a)%p;//合并a降n的规模
n /= 2;
}
return sum;
}
long long q_mul(long long a,long long b,long long p)
{
long long sum = 0;
while(b)
{
if(b&1)//如果b的二进制末尾是零
{
(sum += a)%=p;//a要加上取余
}
(a <<= 1)%=p;//不断把a乘2相当于提高位数
b >>= 1;//把b右移
}
return sum;
}
可以发现两者非常的相似,差别在于结果变量的初值和计算中加号和乘号的区别。
参考文章:
快速幂取模(详细),https://blog.csdn.net/dbc_121/article/details/77646508
大数乘法取模运算(二进制),https://www.cnblogs.com/geloutingyu/p/5886626.html
bool isprime(int x){
if(x==0||x==1) return 0;
if(x==2) return 1;
for(int i=3;i<=sqrt(x);i++){
if(x%i==0) return 0;
}
return 1;
}
单次时间复杂度:\(O(\sqrt{x})\)
判断1-n的素数个数:\(O(x\sqrt{x})\)
时间复杂度:\(O(n\log(\log n))\)
\(N\)组测试数据,求区间\([a,b]\)上的所有质数。
\(N\leq 10^4,a,b\leq 10^6\)
#include<stdio.h>
#include<algorithm>
#include<math.h>
const int maxn=1e6+7;//总的范围规定在这里
using namespace std;
//我们将这个埃氏筛法写成一个函数
bool isprime[maxn];
void sieve(){
for(int i=0;i<=maxn;i++)isprime[i]=true;
isprime[0]=isprime[1]=false;
for(int i=2;i<=maxn;i++){//从2开始往后筛
if(isprime[i]){
for(int j=2*i;j<=maxn;j+=i){
isprime[j]=false;
}
}
}
}
int l,r;
int main(){
//我们在程序刚开始 先调用这个函数
//把这个isprime数组处理成我们想要的样子 用来判断素数
//这就是预处理的思想 我们在开头处理这一次
//把isprime数组 里面 下标是素数的全部变成了true
//后边想判断是不是素数 直接用isprime[i]是不是真就好了
sieve();
int cnt=0;//计数
scanf("%d%d",&l&r);//输入 l和r
for(int i=l;i<=r;i++){//遍历 l到r 判断就行了
if(isprime[i]){
cnt++;
}
}
printf("%d",cnt);
}
输入一个数\(n\),判断他是不是素数,\(N\)组测试数据
\(n\leq 10^6\)
这个时候 就体现了 预处理的重要性
我们先预处理出来 1e6以内的所有素数? 这样不管你输入啥? 我直接去看 是不是素数就好了
预处理 按照一般的算法 20以内的素数需要60次才能判断出来
那1e6以内? 大概需要1e9次(也就是十亿次)
而用埃氏筛法需要70万次
这就是这个算法的效率?
#include<stdio.h>
#include<algorithm>
#include<math.h>
const int maxn=1e6+7;//总的范围规定在这里
using namespace std;
//我们将这个埃氏筛法写成一个函数
bool isprime[maxn];
void sieve(){
for(int i=0;i<=maxn;i++)isprime[i]=true;
isprime[0]=isprime[1]=false;
for(int i=2;i<=maxn;i++){//从2开始往后筛
if(isprime[i]){
for(int j=2*i;j<=maxn;j+=i){
isprime[j]=false;
}
}
}
}
int n;
int main(){
sieve();//预处理
//输入 n
while(scanf("%d",&n)!=EOF){
if(isprime[n]){
printf("Yes\n");
}
else{
printf("No\n");
}
}
}
标签:质数 mat 范围 正文 区间 can art png htm
原文地址:https://www.cnblogs.com/liuziwen0224/p/shulun1.html