【河北省队互测】 gcd BZOJ 2818
Description
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
Input
一个整数N
Output
如题
Sample Input
4
Sample Output
4
HINT
hint
对于样例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
思路
最近看了很多关于gcd和mod的题目。
通过最近几道题目了解了很多=。=
首先有这么一个性质:如果a∈[1,n],b∈[1,m],那么gcd(a,b)|k的有(n/k)*(m/k)组。
那么令f[x]为gcd(a,b)==k的组数,f[k]=(n/k)*(m/k)-f[2k]-f[3k]-f[4k]……
对于这一题来说。。好像是并不可以过的。
那么就有别的性质:
如果a,b∈[1,n],gcd(a,b)==k的组数等价于a,b∈[1,n/k],gcd(a,b)==1的组数。
这就很好求了吧,就是1->n的phi值之和(欧拉函数)*2-1。
首先每组数必须要算两遍,比如(3,5)和(5,3),所以要*2。然后(1,1)不要算两遍,所以再-1。
然后就是如何求出1-n中所有的质数以及欧拉函数了。现场学习线性筛。。
其实我完全不理解啊。。先记住好了。。核心代码如下:
1 phi[1]=1;memset(is_prime,true,sizeof(is_prime)); 2 for(int i=2;i<=n;i++){ 3 if (is_prime[i]){ 4 phi[i]=i-1; 5 prime[++cnt]=i; 6 } 7 for(int j=1;j<=cnt&&i*prime[j]<=n;j++){ 8 is_prime[i*prime[j]]=false; 9 if (i%prime[j]!=0) phi[i*prime[j]]=phi[i]*(prime[j]-1); 10 else{ 11 phi[i*prime[j]]=phi[i]*prime[j]; 12 break; 13 } 14 } 15 }
应该没写错吧。。为了加强记忆默写的。。如果有问题就看下面的那个版本吧,那个是AC了的。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <cmath> 7 #include <algorithm> 8 #include <queue> 9 #include <stack> 10 #include <map> 11 #include <set> 12 #include <list> 13 #include <vector> 14 #include <ctime> 15 #include <functional> 16 #define pritnf printf 17 #define scafn scanf 18 #define sacnf scanf 19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 20 #define Clear(a) memset(a,0,sizeof(a)) 21 using namespace std; 22 typedef unsigned int Uint; 23 const int INF=0x3fffffff; 24 ///==============struct declaration============== 25 26 ///==============var declaration================= 27 const int MAXN=10000050; 28 int n,tot=0,ans=0; 29 int prime[MAXN]; 30 long long phi[MAXN]; 31 bool is_prime[MAXN]; 32 ///==============function declaration============ 33 void Init(); 34 ///==============main code======================= 35 int main() 36 { 37 //#define FILE__ 38 #ifdef FILE__ 39 freopen("input","r",stdin); 40 freopen("output","w",stdout); 41 #endif 42 scanf("%d",&n); 43 Init(); 44 for(int i=1;i<=n;i++) phi[i]+=phi[i-1]; 45 long long ans=0; 46 for(int i=1;i<=tot;i++) 47 ans+=phi[n/prime[i]]*2-1; 48 printf("%lld\n",ans); 49 return 0; 50 } 51 ///================fuction code==================== 52 void Init(){ 53 memset(is_prime,true,sizeof(is_prime));phi[1]=1; 54 for(int i=2;i<=n;i++){ 55 if (is_prime[i]){ 56 phi[i]=i-1; 57 prime[++tot]=i; 58 } 59 for(int j=1;j<=tot;j++){ 60 if (i*prime[j]>n) break; 61 is_prime[i*prime[j]]=false; 62 if (i%prime[j]==0){ 63 phi[i*prime[j]]=phi[i]*prime[j]; 64 break; 65 } 66 else 67 phi[i*prime[j]]=phi[i]*(prime[j]-1); 68 } 69 } 70 }
不要问我那些性质是为什么。。我也布吉岛(╯‵□′)╯︵┻━┻