若一个正整数无法被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
扫描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);
}
}
参考书籍:算法竞赛进阶指南