约数个数和欧拉函数

1.若N=p1^(c1)+p2^(c2)+p3^(c3)+..... p为素数

   约数个数为(c1+1)*(c2+1)*(c3+1)*......

 2. 1到N中 所以约数和\sum_{i=1}^{N}f(i)=NlogN

3.0<=N<=2*1e9 约数个数最多的个数为1600


1.轻拍牛头

信息学奥赛一本通(C++版)在线评测系统 

题意:全部数中除自己外有多少个因数,重复也算

用到性质二算时间复杂度 nlogn

#include <bits/stdc++.h>
using namespace std;
const int N=1000010;
int n;
int a[N],cnt[N],s[N];
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        cnt[a[i]]++;
    }
    for(int i=1;i<N;i++)
        for(int j=i;j<N;j+=i)
        {
            s[j]+=cnt[i];
        }
    for(int i=0;i<n;i++)
        printf("%d\n",s[a[i]]-1);
    return 0;
}

2.樱花

信息学奥赛一本通(C++版)在线评测系统

 

 

等价于求(n!)^2的约数个数 然后就是上一节的阶乘分解的拓展

 

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10,mod=1e9+7;
int prime[N],cnt;
bool st[N];
void init(int n)//筛质数
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) prime[cnt++]=i;
        for(int j=0;prime[j]*i<=n;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int n;
    cin>>n;
    init(n);
    int res=1;
    for(int i=0;i<cnt;i++)//枚举质数
    {
        int p=prime[i];
        int s=0;
        for(int j=n;j;j/=p) s+=j/p;//求p的次方
        res=(ll)res*(2*s+1)%mod;//答案乘上个数
    }
    cout<<res<<endl;
    return 0;
}

 3.反素数

198. 反素数 - AcWing题库

相当于求小于n中约数最多的数的最小数

因为不同的质因子最多有9个,因为2*3*5*7*11*13*17*19*23*29>2e9,所以只需前9个不同质因子即可构成所有的约数

然后2^31>2e9,所以最多枚举到30次方即可,用dfs暴搜来求

 

#include <bits/stdc++.h>
using namespace std;
int primes[]={2,3,5,7,11,13,17,19,23};
int maxd,number;
int n;
typedef long long ll;
void dfs(int u,int last,int p,int s)
{
    if(s>maxd||s==maxd&&p<number)
    {
        maxd=s;
        number=p;
    }
    if(u==9) return ;
    for(int i=1;i<=last;i++)
    {
        if((ll)p*primes[u]>n) break;
        p*=primes[u];
        dfs(u+1,i,p,s*(i+1));
    }
}
int main()
{
    cin>>n;
    dfs(0,30,1,1);
    cout<<number<<endl;
    return 0;
}

4.Hankson的趣味题

200. Hankson的趣味题 - AcWing题库

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int prime[N],cnt;
bool st[N];
int a,b,c,d;
int fcnt;
struct
{
    int p,s;
}f[1601];//存质因数跟次幂
int divide[1601],dcnt;//存约数
int gcd(int a,int b)//求最大公约数
{
    return b?gcd(b,a%b):a;
}
void dfs(int u,int p)//枚举到第u个 当前的约数是p
{
    if(u==fcnt)//假如枚举完了,这是个合法的约数
    {
        divide[dcnt++]=p;
        return;
    }
    for(int i=0;i<=f[u].s;i++)//枚举所有次幂
    {
        dfs(u+1,p);
        p*=f[u].p;//更新一下p
    }
}
void init(int n)//线性筛
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) prime[cnt++]=i;
        for(int j=0;prime[j]*i<=n;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0) break;
        }
    }
}
void solve()
{
    fcnt=dcnt=0;
    int res=0;
    cin>>a>>b>>c>>d;
    int t=d;
    //将d进行分解质因式
    for(int i=0;prime[i]<=t/prime[i];i++)//枚举所有质因子
    {
        int p=prime[i];
        if(t%p==0)
        {
            int s=0;
            while(t%p==0) t/=p,s++;
            f[fcnt++]={p,s};//记录这个质因数跟幂次
        }
    }
    if(t>1) f[fcnt++]={t,1};//假如有剩余,也存起来
    dfs(0,1);//暴力搜索所有约数
    for(int i=0;i<dcnt;i++)//枚举d的所有约数
    {
        int x=divide[i];
        if(gcd(a,x)==b&&(ll)c*x/gcd(x,c)==d) res++;//假如满足条件则答案++
    }
    cout<<res<<endl;
}
int main()
{
    init(100000);//预处理出来质数
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

欧拉函数

1到N中和N互质的数的个数

模板

void init(int n)//欧拉筛
{
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) 
        {
            prime[cnt++]=i;
            pri[i]=i-1;
        }
        for(int j=0;prime[j]*i<=n;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0) 
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}

 1.可见的点

201. 可见的点 - AcWing题库

假如[x,y]x与y不互质,则必能约成最简【x/d,y/d】所以[x,y]这个点会被[x/d,y/d]

这个点挡住,所以只要求与x互质的y的个数加起来就是答案了,因为两边互质的数关于y=x对称,则只需y=x下面的互质数在×2就为答案,因为y=x也有一条则最终的答案+1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int prime[N],cnt;
bool st[N];
int phi[N];
void init(int n)//欧拉筛
{
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
        {
            prime[cnt++]=i;
            phi[i]=i-1;
        }
        for(int j=0;prime[j]*i<=n;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}
int main()
{
    init(1010);//预处理出来欧拉函数
    int T;
    cin>>T;
    for(int i=1;i<=T;i++)
    {
        int n,res=0;
        cin>>n;
        for(int i=1;i<=n;i++) res+=2*phi[i];//求答案
        printf("%d %d %d\n",i,n,res+1);
    }
    return 0;
}

2.最大公约数

220. 最大公约数 - AcWing题库

1 - N中gcd(a,b)=素数d,则gcd(a/d,b/d)=1,则a/d,b/d互质 则相当于在1 - N/d中 GCD(x,y)=1的个数

x,y属于(1~n/d)则映射到二维坐标就跟上一题的求法一样了,就问1~n/d之间的互质数对个数,所以提前预处理出来前缀和即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+10;
int prime[N],cnt;
bool st[N];
int phi[N];
ll s[N];//记录欧拉函数的前缀和
void init(int n)//欧拉筛
{
    phi[1]=0;//下标题目从1开始
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
        {
            prime[cnt++]=i;
            phi[i]=i-1;
        }
        for(int j=0;prime[j]*i<=n;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    phi[1]=0;
    for(int i=1;i<=n;i++) s[i]=s[i-1]+phi[i];//处理出来欧拉数的前缀和
}
int main()
{
    int n;
    ll res=0;
    cin>>n;
    init(n);//欧拉筛
    for(int i=0;i<cnt;i++)//枚举所有的质数d
    {
        int d=prime[i];
        res+=s[n/d]*2+1;//答案加上n/d的互质数队,跟上一题一样
    }
    printf("%lld\n",res);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值