NKOJ 3800 分解质因数(欧拉函数+线性筛)

来源:互联网 发布:vb.net excel 数据库 编辑:程序博客网 时间:2024/05/22 04:27

P3801分解质因数

问题描述

记Pi表示正整数i的质因数集合。

已知正整数n,求满足下列条件的有序正整数对(a,b)的数目:

(1)1<=a<=b<=n
(2)t为a,b的最大公约数,Pt是Pn的子集

输入格式

一个正整数n.

输出格式

一个正整数,表示合题意的有序正整数对的数目.

样例输入 1

6

样例输出 1

20

样例输入 2

7

样例输出 2

19

数据范围

50%的数据1<=n<=2000;

100%的数据1<=n<=1000000.


此题有两种做法。

做法一:先介绍一种比较简单粗暴的。
我们考虑一个数d,满足PdPn的子集,这样的d是比较容易求的,只需要求出n的质因数分解后用线性筛就可以处理,但是本题可以直接暴力一点预处理。

总之,我们求出了d,那么现在需要考虑对于每一个d,有多少个数对(A,B)满足gcd(A,B)=d,那么根据gcd的性质,有gcd(Ad,Bd)=1
那么显然我们只需要找出在1nd的范围中,有多少对互质的整数即可,那么显然是ndi=1ϕ(i),那么ϕ的前缀和Sϕ可以用线性筛处理,然后枚举dSϕ(nd)累加起来就是答案。


代码:

#include<stdio.h>#include<iostream>#include<algorithm>#define N 1000005#define ll long longusing namespace std;ll n,phi[N],S[N],P[N],tot,ans;bool mark[N];int main(){    ll i,j;    scanf("%lld",&n);phi[1]=1;S[1]=1;    for(i=2;i<=n;i++)    {        if(!phi[i])phi[i]=i-1,P[++tot]=i;        for(j=1;j<=tot&&P[j]*i<=n;j++)        if(i%P[j])phi[i*P[j]]=phi[i]*(P[j]-1);        else {phi[i*P[j]]=phi[i]*P[j];break;}        S[i]=S[i-1]+phi[i];    }    for(i=1;i<=tot;i++)if(n%P[i])for(j=P[i];j<=n;j+=P[i])mark[j]=1;    for(i=1;i<=n;i++)if(!mark[i])ans+=S[n/i];    printf("%lld",ans);}

做法二:
做法二比较的巧妙,我们可以认为在Pn中的质数不是质数,那么题设条件就变成了求有多少对互质的数对,那么显然是欧拉函数求解,但是由于质数是改动过的,我们记他为ϕ(x),那么因为这个函数与欧拉函数基本是一样的,那么他显然是积性函数,那么就可以用线性筛来搞。
具体来说,我们在普通的线性筛中,遇到质数时判断一下,如果这个质数在Pn中,那么ϕ(x)=x,否则ϕ(x)=x1,然后合数还是通过积性函数性质来搞。


代码:

#include<stdio.h> #include<iostream> #include<cmath> using namespace std; const int N=20000050; int n,phi[N],prime[N]; bool mark[N],p[N]; void linear() {     int i,j,tot=0; phi[1]=1;    for(i=2;i<=n;i++)    {        if(!phi[i])        {            if(!p[i])phi[i]=i-1;            else phi[i]=i;            prime[++tot]=i;        }         for(j=1;j<=tot&&prime[j]*i<=n;j++)         if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}        else phi[i*prime[j]]=phi[i]*(phi[prime[j]]);    }} main() {     int i,j,k;     cin>>n;     int tmp=n;     for(i=2;i*i<=n&&tmp!=1;i++)     if(tmp%i==0)     {        while(tmp%i==0)tmp/=i;        p[i]=true;    }     if(tmp!=1)p[tmp]=true;     linear();    long long ans=0;    for(i=1;i<=n;i++)ans+=1LL*(phi[i]);    cout<<ans;}
阅读全文
0 0