[bzoj2818]Gcd 欧拉函数
2017-08-25 19:58
344 查看
题目链接:bzoj2818
—————————————-
给定一个正整数n,求满足1≤x,y≤n,且gcd(x,y)为质数的数对(x,y)有多少个。(1≤n≤10000000)
注:数对(2,4)和数对(4,2)是不同的数对.
—————————————-
假如我们要对上面那个式子进行化简,那么抱歉,我是没有那么高的水平。那怎么解决这个问题呢?
我们不妨换个角度思考,既然题目想统计的是gcd(x,y)为质数的数对,那么我们可以枚举1~n之间的每一个质数pi,分别计算每个pi的贡献,也就是计算每个pi是多少对数的最大公约数。
我们假设a、b的最大公约数是质数p,那么我们可以把a、b写成这样的形式:a=p×a1, b=p×b1.
其中,a1与b1一定互质,否则a和b的最大公约数就不是p了。
由于我们枚举的是p,所以已经确定了p,故我们只要统计有多少对a1、b1互质就能知道每个p有多少贡献了。
由于a、b的取值范围是1~n,所以a1、b1的取值范围均是1~np,我们可以枚举a1,计算1~a1中有多少个数与a1互质即可,也就是:∑i=1np∑j=1i[gcd(i,j)=1]=∑i=1npφ(i).
我们可以通过线性筛求得1~n中所有数的欧拉函数,记录前缀和来求得上式的值。
由于题目里的规定:(4,2)和(2,4)是不同数对,所以我们需要将这样统计的结果乘2。
还有一个细节需要注意:数对(pi,pi)的最大公约数也是pi,上面所给的计算式中将结果乘了2,也就是将数对(x,y)交换位置变成(y,x)。然而(pi,pi)交换之后还是(pi,pi),所以需要将这一部分多计算的答案减去,也就是减去1~n之间质数的个数。
综上:Ans=(2×∑i=1tot∑j=1npiφ(j))−tot.
—————————————-
—————————————-
—————————————-
——wrote by miraclejzd
—————————————-
概述
题目大意如下。给定一个正整数n,求满足1≤x,y≤n,且gcd(x,y)为质数的数对(x,y)有多少个。(1≤n≤10000000)
注:数对(2,4)和数对(4,2)是不同的数对.
—————————————-
题解
记答案为Ans,那么有:Ans=∑i=1n∑j=1n[(∑k=2gcd(i,j)[gcd(k,gcd(i,j))=1])=1].假如我们要对上面那个式子进行化简,那么抱歉,我是没有那么高的水平。那怎么解决这个问题呢?
我们不妨换个角度思考,既然题目想统计的是gcd(x,y)为质数的数对,那么我们可以枚举1~n之间的每一个质数pi,分别计算每个pi的贡献,也就是计算每个pi是多少对数的最大公约数。
我们假设a、b的最大公约数是质数p,那么我们可以把a、b写成这样的形式:a=p×a1, b=p×b1.
其中,a1与b1一定互质,否则a和b的最大公约数就不是p了。
由于我们枚举的是p,所以已经确定了p,故我们只要统计有多少对a1、b1互质就能知道每个p有多少贡献了。
由于a、b的取值范围是1~n,所以a1、b1的取值范围均是1~np,我们可以枚举a1,计算1~a1中有多少个数与a1互质即可,也就是:∑i=1np∑j=1i[gcd(i,j)=1]=∑i=1npφ(i).
我们可以通过线性筛求得1~n中所有数的欧拉函数,记录前缀和来求得上式的值。
由于题目里的规定:(4,2)和(2,4)是不同数对,所以我们需要将这样统计的结果乘2。
还有一个细节需要注意:数对(pi,pi)的最大公约数也是pi,上面所给的计算式中将结果乘了2,也就是将数对(x,y)交换位置变成(y,x)。然而(pi,pi)交换之后还是(pi,pi),所以需要将这一部分多计算的答案减去,也就是减去1~n之间质数的个数。
综上:Ans=(2×∑i=1tot∑j=1npiφ(j))−tot.
—————————————-
代码
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #define ll long long #define For(i,j,k) for(register int i=j; i<=(int)k; ++i) #define Forr(i,j,k) for(register int i=j; i>=(int)k; --i) #define INF 0x3f3f3f3f using namespace std; const int maxn = 10000005; int n, tot; int pri[maxn/10], phi[maxn]; ll Ans; ll sum[maxn]; bool vis[maxn]; inline void init(int n){ sum[1] = phi[1] = 1; For(i, 2, n){ if(!vis[i]){ pri[++tot] = i; phi[i] = i-1; } sum[i] = sum[i-1]+phi[i];//记录前缀和. for(register int j=1,x; j<=tot&&(x=i*pri[j])<=n; ++j){ vis[x] = true; if(i%pri[j] == 0){ phi[x] = phi[i]*pri[j]; break; } else phi[x] = phi[i]*(pri[j]-1); } } }//线性筛. int main(){ scanf("%d", &n); init(n);//线性筛求得质数及欧拉函数. Ans = 0; For(i, 1, tot) Ans += sum[n/pri[i]];//统计答案. Ans = (Ans<<1)-tot;//减去重复计算的部分. printf("%lld", Ans); return 0; }
—————————————-
小结
本题难点在于概念转换,将统计数对贡献变成统计质数贡献,后者由于有更多的性质可以利用,比如可以转化成欧拉函数,所以更方便解题。—————————————-
——wrote by miraclejzd
相关文章推荐
- 【欧拉函数+线性筛】bzoj2818: Gcd
- 【bzoj2818】Gcd 欧拉函数
- 【欧拉函数】BZOJ2818-GCD
- bzoj 2818 Gcd 欧拉函数求和
- _bzoj2818 Gcd【线性筛法 欧拉函数】
- BZOJ 2818 GCD(欧拉函数)
- BZOJ2818: Gcd 欧拉函数求前缀和
- Bzoj-2818 Gcd 欧拉函数
- bzoj 2818 Gcd 【欧拉函数】
- BZOJ 2818 GCD 欧拉函数
- bzoj 2818 Gcd(欧拉函数 | 莫比乌斯反演)
- BZOJ 2818: Gcd [欧拉函数 质数 线性筛]【学习笔记】
- Bzoj 2818: Gcd 莫比乌斯,分块,欧拉函数,线性筛
- [BZOJ2818] Gcd (数论,欧拉函数,线性筛)
- BZOJ 2818 Gcd (莫比乌斯反演 或 欧拉函数)
- BZOJ2818 Gcd(欧拉函数)
- [BZOJ2818] gcd - 欧拉函数+筛法
- 【BZOJ】2818: Gcd(欧拉函数/莫比乌斯)
- BZOJ 2818: Gcd( 欧拉函数 )
- 【BZOJ】2818 Gcd 欧拉函数