BZOJ2818 Gcd
Posted Blogggggg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2818 Gcd相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/problem/HYSBZ-2818
知识点: 欧拉函数、积性函数
解题思路:
对于有序数对 \((x,y)\),若其满足 \(gcd(x,y)=p\)(\(p\)为质数),我们可以将 \(x\) 和 \(y\) 同时除以 \(p\),上式就变成了\(gcd(x‘,y‘)=1\),那么对于一个 \(x\) ,满足条件的 \(y\) 的个数为 \(\varphi (x)\) 。对于 \([1,N]\) 中的每一个质数 \(p\),我们可以通过求 \([1,N/p]\) 这个范围内的欧拉函数的总和来求得 \(gcd(x,y) = p\) 的无序数对的个数,考虑到题目中的数对是有序的,所以还需要将无序数对乘二。还有一点是当 \(x\) 和 \(y\) 都是相同的质数时需要特殊处理。
求前 \(n\) 个数的欧拉函数值的算法主要就是利用欧拉函数是积性函数的性质和一条欧拉函数的经典计算式:
\(\varphi(n) = \prod_{i=1}^{k} (p_i-1)p_i^{c_i-1}\).
AC代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long LL; 5 const int maxn = 1e7+5; 6 bool check[maxn]; 7 int phi[maxn]; 8 int prime[maxn>>1],tot; 9 10 void init(int N){ 11 phi[1]=1; 12 tot=0; 13 for(int i=2;i<=N;i++){ 14 if(!check[i]){ 15 phi[i]=i-1; 16 prime[tot++]=i; 17 } 18 for(int j=0;j<tot&&(LL)i*prime[j]<=N;j++){ 19 check[i*prime[j]]=true; 20 if(i%prime[j]==0){ 21 phi[i*prime[j]]=phi[i]*prime[j]; 22 break; 23 } else{ 24 phi[i*prime[j]]=phi[i]*(prime[j]-1); 25 } 26 } 27 } 28 } 29 30 int main(){ 31 LL ans=0; 32 int N; 33 scanf("%d",&N); 34 init(N); 35 36 for(int i=0;i<tot;i++){ 37 for(int j=1;j<=N/prime[i];j++) 38 ans+=phi[j]*2; 39 ans--; 40 } 41 printf("%lld\n",ans); 42 return 0; 43 }
以上是关于BZOJ2818 Gcd的主要内容,如果未能解决你的问题,请参考以下文章