GCD HDU - 1695

原题链接

考察:容斥原理+埃氏筛+质因数分解

思路:

      gcd(x,y) = k 等价于gcd(x/k,y/k) = 1.设 u = x/k,v= y/k.找出范围内u与v互质的对数.

      这里可以用欧拉函数做,枚举1~d/k每一个数i.如果i在b/k范围内就是欧拉函数值,如果>b/k就是该欧拉函数值-b/k~i中与gcd(i,j)!=1的数.

      那么问题是如何找gcd(i,j)!=1的数.由之前的Hankson趣味题可知,公约数是i,j所有质因数的指数取最小值的乘积.如果gcd!=1,那么gcd能分解为质数.所以将i分解为质因数乘积.筛去b/k~i中,该质因数的倍数,但是存在是多个质因数的倍数的数,所以需要用到容斥原理.最后将答案累加即可.

注意:存在k==0的情况,此时答案为0

与上面思路很像的思路2:

        同样是枚举,但是是枚举u,1~b/k中计算求出每个数的质因数,用容斥原理筛去倍数.答案是d/k-i-容斥原理求出的倍数个数

蒟蒻是参考了思路2的思路

关于分解质因数:

       这里用了埃氏筛的思想,有点妙,本蒟蒻一直以为只能筛处质数再一个个分解..233

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N = 100010;
 7 int prime[N],cnt,a,b,c,d,k;
 8 bool st[N];
 9 vector<int> v[N];
10 void GetPrime(int n)
11 {
12     st[0] = st[1] = 1;
13     for(int i=2;i<=n;i++)
14     {
15         if(st[i]) continue;
16         v[i].push_back(i);//i可被自己分解 
17         for(int j=i*2;j<=n;j+=i)
18         {
19             st[j] = 1;
20             v[j].push_back(i);//j可被哪些质数分解 
21         }
22     }
23 }
24 int main() 
25 {
26     GetPrime(1e5);
27     int T,kcase= 0;
28     scanf("%d",&T);
29     while(T--)
30     {
31         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
32         printf("Case %d: ",++kcase);
33         if(!k||k>b||k>d) { printf("0\n"); continue;}
34         b/=k,d/=k;
35         if(b>d) swap(d,b);//将x视为小的数
36         ll ans = d;
37         for(int i=2;i<=b;i++) //ans应为所有数-与i不互质的数 
38         {
39             int sz = v[i].size();//枚举每个1~b的数 
40             ll t = 0;//i+1到d中倍数的数目 
41             for(int j=1;j<1<<sz;j++)//枚举i的质因数的倍数的集合 
42             {
43                 int cnt = 0; ll tmp = 1;
44                 for(int k=0;k<sz;k++)//选哪些集合 
45                 {
46                     if(j>>k&1)
47                     {
48                         cnt++;
49                         if(v[i][k]*tmp>d)//如果范围超过不计入 
50                         {
51                             tmp = -1;
52                             break;
53                         }
54                         tmp*=v[i][k];
55                     }
56                 }
57                 if(tmp!=-1)//ans = i+1~d的是i质因数倍数的个数 
58                 {
59                     if(cnt&1) t+=d/tmp-i/tmp;
60                     else t-=d/tmp-i/tmp;
61                 }
62             }
63             ans += (ll)d-i-t;
64         }
65         printf("%lld\n",ans);
66     }
67     return 0;
68 }

 

 

2021.06.12 学了Mobius函数,可以利用整除分块与前缀和的形式优化求与i互质的数的个数.时间复杂度可以优化到2*T*sqrt(n).但是注意这道题是(x,y),(y,x)是计入同一个.但是只会在(1,min(b,d)里计入相同的,所以将(1,min(b,d))的ans/2再减去即可.

posted @ 2021-01-30 21:20  acmloser  阅读(79)  评论(0编辑  收藏  举报