数论问题之质数

质数定义

若一个正整数无法被1和它自身之外的任何自然数整除,则称该数为质数(素数),否则该数为合数。

质数的判定用试除法:

bool is_prime(int n){
	if(n<2) return false;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0) return false;
	} 
	return true;
}

质数的筛选方法:
埃式筛法和线性筛法:链接(之前写过,就不写了)。

质因数分解

算术基本定理:
任何一个不大于1的正整数都能唯一分解为有限个质数的乘积,可写作
N=p1c1p2c2p3c3……pmcm
其中ci为正整数,pi为质数,满足p1<p2<p3<……<pm.
试除法
扫描2-sqrt(n)的每一个数d,若d能整除n,则从n中除掉所有的因子d,同时可以累计d的个数。最后特别的需要判定,若最后n>1,则说明n为质数。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int p[N],c[N],m;//p数组表示n的因子,c数组表示对应的因子的个数
void devide(int n){
	memset(c,0,sizeof(c));
	m=0;//m记录的多少个因子
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			p[++m]=i;
			while(n%i==0) n/=i,c[m]++; 
		}
	}
	if(n>1) c[++m]=n,c[m]++;
	for(int i=1;i<=m;i++){
		cout<<p[i]<<'^'<<c[i]<<endl;
	}
}
int main(){
	int n;
	cin>>n;
	devide(n);
	system("pause");
}

poj1845Sumdiv
题意:求AB的所有约数之和mod9901.
思路:
把A分解质因数A=p1c1p2c2p3c3……pmcm
AB=p1B*c1p2B*c2p3B*c3……pmB*cm
根据乘法分配律,AB的所有约数之和就是:
(1+p11+p12+p13+……+p1B*c1)*(1+p21+p22+p23+……+p2B*c2) * …… *(1+pm1+pm2+pm3+……+pmB*cm)
在使用分治法求sum(p,c)=1+p1+p2+p3+……+pc
当c为奇数时有偶数项,当c为偶数时有奇数项
c为奇数:sum(p,c)=1+p1+p(c-1)/2+……+p(c+1)/2+……+pc
=(1+p1+……+p(c-1)/2)+p(c+1)/2 * (1+p1+……+p(c-1)/2)
=(1+p(c+1)/2) * (1+p1+……+p(c-1)/2)
=(1+p(c+1)/2) * sum(p,(c-1)/2)
c为偶数:sum(p,c)=1+p1+p(c-2)/2+……+pc/2+……+pc-1+pc
==(1+pc/2) * sum(p,c/2-1)+pc
代码:

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;
const int mod=9901;
vector<pair<int ,int> > v;
int ksm(int p,int c){
	int ans=1;
	p%=mod;
	while(c){
		if(c&1) ans=1ll*ans*p%mod;
		p=1ll*p*p%mod;
		c>>=1;
	}
	return ans;
}
int get_sum(int p,int c){
	if(!p) return 0;
	if(!c) return 1;
	if(c&1) return 1ll*(ksm(p,(c+1)/2)+1)*get_sum(p,(c-1)/2)%mod;
	else return (1ll*(ksm(p,c/2)+1)*get_sum(p,c/2-1)+ksm(p,c))%mod;
}
int main(){
	int a,b;
	cin>>a>>b;
	for(int i=2;i*i<=a;i++){
		if(a%i==0){
			int sum=0;
			while(a%i==0){
				sum++;
				a/=i;
			}
			v.push_back(make_pair(i,sum));
		}
	}
	if(a>1) v.push_back(make_pair(a,1));
	int ans=1;
	for(int i=0;i<v.size();i++){
		int p=v[i].first,c=v[i].second;
		ans=1ll*ans*get_sum(p,b*c)%mod;
	}
	cout<<ans<<endl;
}

poj2689Prime Distance
题意:
给定俩个整数L,R(1<=L<=R<=231,R-L<=106),求闭区间[L,R]内 相邻来个数的差最大是多少,输出这俩个质数。
思路:因为L,R的范围很大不能使用暴力做法,但是R-L的值小,我们可以先筛选出2-sqrt( R)之间的左右质数,然后在用这些质数去筛选L-R内的所有质数,最终没有被标记的就是L-R内的质数。
先处理2-sqrt(231)内的质数,sqrt(231)约等于46340.(可以打表也可以使用线性筛)。
代码:

#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;
const int M=46430,N=1e6+10,INF=0x7fffffff;
vector<int> p,ans;
bool v[N];
int main(){
	memset(v,1,sizeof(v));
	for(int i=2;i<=M;i++){
		if(v[i]){
			p.push_back(i);
			for(int j=2;j<=M/i;j++) v[i*j]=0;
		}
	}
	int l,r;
	while(cin>>l>>r){
		memset(v,1,sizeof(v));
		ans.clear();
		if(l==1) v[0]=0;
		for(int i=0;i<p.size();i++){
			for(int j=(l-1)/p[i]+1;j<=r/p[i];j++){
				if(j>1) v[p[i]*j-l]=0;
			}
		}
		for(unsigned int i=l;i<=r;i++)
			if(v[i-l]) 
				ans.push_back(i);
		int minn=INF,maxx=0,x1,x2,y1,y2; 
		for(int i=0;i<ans.size()-1;i++){
			int d=ans[i+1]-ans[i];
			if(d<minn){
				minn=d;
				x1=ans[i];
				y1=ans[i+1];
			}
			if(d>maxx){
				maxx=d;
				x2=ans[i];
				y2=ans[i+1];
			}
		}
		if (!maxx) puts("There are no adjacent primes.");
		else printf("%d,%d are closest, %d,%d are most distant.\n", x1, y1, x2, y2);
	}
}

CH3101阶乘分解
题意:
给定整数N(1<=N<=106),试把阶乘N!分解质因数,按照算术基本定理的形式输出分解结果中的pi和c1.
思路:
N!的质因数p的个数就是1-N中每个数包含质因数p的个数和,包含质因子p的个数为N/p,接下来计算p2的个数为N/p2,直到N/(longN/longp),加在一块就是p的个数和。
代码:

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
int isprime[1000000+10];
int prime[1000000+10];
int c;
void Prime(int n) {
    memset(isprime,1,sizeof(isprime));
    isprime[0]=isprime[1]=0;
    for(int i=2;i<=n;i++) {
        if(isprime[i]) prime[c++] = i;
        for(int j = 0; (j<c && i*prime[j]<=n);j++) {
            isprime[i*prime[j]]=0;
            if(!(i%prime[j])) break;
        }
    }
}
int main(){
	int n;
	cin>>n;
	Prime(n);
	for(int i=0;i<c;i++) {
		int p=prime[i];
		int sum=0;
		for(int j=n;j>=1;j/=p) sum+=j/p;
		printf("%d %d\n",p,sum);
	}
}

参考书籍:算法竞赛进阶指南

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值