分解质因数(区分质因子和约数!!)
void divide(int x){
for(int i=2;i<=x/i&&x>1;i++){
if(x%i==0){
int s=0;
while(x%i==0){
s++;
x/=i;
}
cout<<i<<" "<<s<<endl;
}
}
if(x>1) cout<<x<<" "<<1<<endl;
cout<<endl;
}
分解N!的质因数
多个数相乘的质因子次数,等于将每个数的质因子次数相加
先筛质数,然后计算每个质数在1~N出现的次数之和
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n;
int prime[N],cnt;
bool vis[N];
int res[N];
void get_prime(int n){
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++cnt]=i;
vis[i]=true;
}
for(int j=1;prime[j]*i<=n;j++){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
int main(){
cin>>n;
get_prime(n);
for(int i=1;i<=cnt;i++){
int p=prime[i],s=0;
for(int j=n;j;j/=p){
s+=j/p;
}
res[p]+=s;
}
for(int i=1;i<=cnt;i++){
int p=prime[i];
if(res[p]!=0){
cout<<p<<" "<<res[p]<<endl;
}
}
}
筛质数
埃式筛 O(nloglogn)
线性筛 O(n)
int prime[N];
bool vis[N];
int cnt;
//埃式筛
void get_prime1(int n){
for(int i=2;i<=n;i++){
if(vis[i]) continue;
prime[cnt++]=i;
for(int j=2;j*i<=n;j++){
vis[i*j]=true;
}
}
}
//线性筛
void get_prime2(int n){
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[cnt++]=i;
}
//注意,不管是不是质数都要执行这里
for(int j=0;prime[j]*i<=n;j++){
int t=prime[j]*i;
vis[t]=true;
if(i%prime[j]==0) break;
}
}
}
质数距离(筛大区间[l,r]的质数)
1≤L<U≤2^31−1 先筛出小区间的质数,对于一个合数x,必然存在小于sqrt(x)的质因子,所以线性筛筛出[1,50000]的质数(50000 = sqrt(2^31))
对于区间[L,U],使用埃筛的思想,对于每个质数p,筛掉区间内p的倍数,最终得到的即为[L,U]内的质数 (注意将[L,U]映射到[0,U-L])
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=5e4+5,M=1e6+5;
int prime[N];
int pcnt;
bool vis[N];
void init(){//筛出1~50000的质数 (50000 = sqrt(2^31))
for(int i=2;i<N;i++){
if(!vis[i]){
prime[++pcnt]=i;
}
for(int j=1;i*prime[j]<N;j++){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
int st[M];
int pprime[M];
int cnt;
//对于一个合数x,必然存在小于sqrt(x)的质因子
int main(){
init();
int l,r;
while(cin>>l>>r){
memset(st,false,sizeof st);
for(int i=1;i<=pcnt;i++){
ll p=prime[i];
//埃筛 p是质数 筛掉[l,r]内p的倍数
//(l+p-1)/p 大于L且离L最近的P的倍数
for(ll j=max(2*p,(l+p-1)/p*p);j<=r;j+=p){
//[l,r]的第j-l个被筛掉
st[j-l]=true;
}
}
//[l,r]的质数
cnt=0;
for(int i=0;i<=r-l;i++){
if(!st[i]&&i+l>=2){
pprime[++cnt]=i+l;
}
}
//枚举相邻的两个质数
if(cnt<2){
printf("There are no adjacent primes.\n");
}else{
int minpos=0,maxpos=0;
int minn=0x3f3f3f3f,maxn=-1;
for(int i=1;i+1<=cnt;i++){
int d=pprime[i+1]-pprime[i];
if(d<minn){
minn=d;
minpos=i;
}
if(d>maxn){
maxn=d;
maxpos=i;
}
}
printf("%d,%d are closest, %d,%d are most distant.\n",pprime[minpos],pprime[minpos+1],pprime[maxpos],pprime[maxpos+1]);
}
}
}
求约数
vector<int> get_divisors(int x)
{
vector<int> res;
//从i开始,不改变x
for(int i=1;i<=x/i;i++){
if(x%i==0){
res.push_back(i);
if(i!=x/i) res.push_back(x/i);
}
}
sort(res.begin(), res.end());
return res;
}
约数个数 约数之和
ll res;
map<int,int> mp;
//如果分解完质因数后,N = p1^c1 * p2^c2 * ... *pk^ck
//约数个数等于 (c1 + 1) * (c2 + 1) * ... * (ck + 1)
//约数之和等于 (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)
void divide(int x){
for(int i=2;i<=x/i;i++){
if(x%i==0){
int s=0;
while(x%i==0){
s++;
x/=i;
}
mp[i]+=s;
}
}
if(x>1) mp[x]++;
}
//约数个数
ll solve1(){
ll res=1;
for(auto t:mp){
res*=(t.second+1);
res%=mod;
}
return res;
}
//约数之和
ll solve2(){
ll res=1;
for(auto t:mp){
int p=t.first;
int c=t.second;
ll s=1;
while(c--)//算 p1^0 + p1^1 + ... + p1^c1的技巧
s=(s*p+1)%mod;
res*=s%mod;
res%=mod;
}
return res;
}
int main(){
int n;cin>>n;
//求x=a0*a1*a2*....的约数个数/约数之和
//先分解x质因数
for(int i=1;i<=n;i++){
cin>>a[i];
divide(a[i]);
}
//约数个数
cout<<solve1()<<endl;
//约数之和
cout<<solve2()<<endl;
}
1~N各自的约数之和
for(int i=1;i<=n;i++) //约数i
for(int j=2;i*j<=n;j++) //i*j的约数包含i
sum[i*j]+=i;
题记
轻拍牛头
TLE代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,M=1e6+5;
int f[M],w[N];
int cnt[M];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
cnt[w[i]]++;
}
for(int i=1;i<=n;i++){
for(int j=2;w[i]*j<M;j++){
f[w[i]*j]++;
}
}
for(int i=1;i<=n;i++){
printf("%d\n",f[w[i]]+cnt[w[i]]-1);
}
}
由于数有很多重复的数,而重复的数答案是相同的,所以只需要计算一次,枚举数的范围,对于一个数i,为i*j都加上i出现的次数,相当于同时计算了重复的i,最后算答案时去掉自己即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,M=1e6+5;
int f[M],w[N];
int cnt[M];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
cnt[w[i]]++;
}
//一样的数只计算一次
for(int i=1;i<M;i++){
if(!cnt[i]) continue;
for(int j=1;i*j<M;j++){
f[i*j]+=cnt[i];
}
}
for(int i=1;i<=n;i++){
printf("%d\n",f[w[i]]-1);
}
}
樱花
反素数
求不超过N的范围中,约数最多的数的最小值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
int prime[]={2,3,5,7,11,13,17,19,23};
int res,maxn;
int n;
//第u个质因子 上个质因子幂数last 当前数num 约数个数sum
void dfs(int u,int last,int num,int sum){
if(sum>maxn||(sum==maxn&&num<res)){
maxn=sum;
res=num;
}
if(u==9) return;
for(int i=1;i<=last;i++){
if((ll)num*prime[u]>n) return;
num*=prime[u];
dfs(u+1,i,num,sum*(i+1));
}
}
int main(){
cin>>n;
dfs(0,30,1,1);
cout<<res<<endl;
}
Hankson的趣味题
先筛质数,用质数分解b的质因子,对所有质因子DFS得到b的所有约数,逐个判断
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=5e4+5;
int prime[N];
int pcnt;
bool vis[N];
void init(){
for(int i=2;i<N;i++){
if(!vis[i]){
prime[++pcnt]=i;
}
for(int j=1;i*prime[j]<N;j++){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
int res;
int x[N];
int xcnt;
PII f[N];
int fcnt;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
//枚举质因子和次幂 相乘得到所有约数
void dfs(int u,int p){
if(u==fcnt+1){
x[++xcnt]=p;
return;
}
for(int i=0;i<=f[u].second;i++){
dfs(u+1,p);
p*=f[u].first;
}
}
int main(){
int t;cin>>t;
init();
while(t--){
int a,b,c,d;cin>>a>>b>>c>>d;
int t=d;
fcnt=0;
for(int i=1;prime[i]<=t/prime[i];i++){
if(t%prime[i]==0){
int s=0;
while(t%prime[i]==0){
t/=prime[i];
s++;
}
f[++fcnt]={prime[i],s};
}
}
if(t>1) f[++fcnt]={t,1};
xcnt=0;
dfs(1,1);
res=0;
for(int i=1;i<=xcnt;i++){
if(gcd(x[i],a)==b&&(ll)x[i]*c/gcd(x[i],c)==d){
res++;
}
}
cout<<res<<endl;
}
}
约数
判断一个数的约数个数是否为3(不能暴力)
① 结论:如果一个数的约数个数是奇数,那么它一定是一个平方数,即sqrt(x)*sqrt(x)==x
②
如果约数个数为3,最多只能有一个质因子(即约数除了1和x,只剩一个质因子),则a+1=3 ,即 a=2,也就是说x是某个质数的平方,判断sqrt(x)是否为质数即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,M=1e6+5;
int prime[M];
int cnt;
bool vis[M];
void init(){
for(int i=2;i<M;i++){
if(!vis[i]){
prime[++cnt]=i;
}
for(ll j=1;prime[j]*i<M;j++){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
bool judge(ll x){
//1特判
if(x==1) return false;
//如果一个数的约数个数是奇数,那么它一定是一个平方数
ll t=sqrt(x);
if(t*t!=x) return false;
if(vis[t]) return false;
return true;
}
int main(){
init();
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
ll x;
scanf("%lld",&x);
if(judge(x)){
printf("YES\n");
}else{
printf("NO\n");
}
}
}
约数之和
A的约数之和为(1+p^1+p^2+....+p^k)*......
A^B的约数之和为(1+p^(1*B)+p^(2*B)+....+p^(k*B))*......
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int N=5e7+5,mod=9901;
int a,b;
ll res=1;
int qmi(int a,int k){
int res=1;
while(k){
if(k&1) res=(ll)res*a%mod;
k>>=1;
a=(ll)a*a%mod;
}
return res;
}
//1+p^1+p^2+....+p^k
int sum(int p,int k){
if(k==0) return 1;
if(k&1){
return (1+qmi(p,k/2+1))*sum(p,k/2)%mod;
}else{
return (p%mod*sum(p,k-1)+1)%mod;
}
}
int main(){
scanf("%d%d",&a,&b);
for(int i=2;i<=a/i;i++){
if(a%i==0){
int s=0;
while(a%i==0){
a/=i;
s++;
}
//A的约数之和为(1+p^1+p^2+....+p^k)*(1+p^1+p^2+....+p^k)...
//A^B的约数之和为(1+p^(1*B)+p^(2*B)+....+p^(k*B))*(1+p^(1*B)+p^(2*B)+....+p^(k*B))...
res=(ll)res*sum(i,s*b)%mod;
}
}
if(a==0){
cout<<0;
return 0;
}
if(a!=1){
res=(ll)res*sum(a,b)%mod;
}
cout<<res;
}