hdu 5072 莫比乌斯反演

hdu 5072 莫比乌斯反演
题意:
给出n个数a1,a2,...,an, 从中选出三个数a,b,c,且这三个数符合[(a,b)=(b,c)=(a,c)=1] || [(a,b)!=1 && (b,c)!=1 && (a,c)!=1] 其中(x,y)表示x,y的最大公约数。求符合这个条件的三元组的个数。

限制:
3 <= n <= 1e5; 1 <= ai <= 1e5

思路:
设bi为与ai互质的数的个数,则符合条件 !(((a,b)=(b,c)=(a,c)=1) || ((a,b)!=1 && (b,c)!=1 && (a,c)!=1)) 的三元组的个数为:
t=(sigma(1~n)bi*(n-1-bi))/2
可以看到C(n,3)-t即为答案。
下面证明上面式子的由来:
对于任意符合条件的a,b,c有以下6种情况:
1. (a,b)=1 && (a,c)!=1 && (b,c)=1
2. (a,b)=1 && (a,c)!=1 && (b,c)!=1
3. (a,b)!=1 && (a,c)=1 && (b,c)=1
4. (a,b)!=1 && (a,c)=1 && (b,c)!=1
5. (a,b)=1 && (a,c)=1 && (b,c)!=1
6. (a,b)!=1 && (a,c)!=1 && (b,c)=1
我们可以发现bi*(n-1-bi)只覆盖了上面的1~4的情况,但我们又发现剩下两种情况可以由b或c来覆盖
其实对于1~6的情况,每种情况都被覆盖了两遍
1. 被a,c覆盖
2. 被a,b覆盖
...
所以是所有的加起来/2

然后问题就被化简为对于每个数,在复杂度内求和它互质的数的个数,这个可以用容斥做,也可以用莫比乌斯反演来做
对于一个给定的数x0
设f(k)为gcd(x0,x)=k的x的数目
设F(k)为gcd(x0,x)为k的倍数的x的数目,然后发现F(k)为拥有因子k的ai的数目,这个可以用O(sqrt(ai))枚举因子预处理出来。

/*hdu 5072
  题意:
  给出n个数a1,a2,...,an, 从中选出三个数a,b,c,且这三个数符合[(a,b)=(b,c)=(a,c)=1] || [(a,b)!=1 && (b,c)!=1 && (a,c)!=1] 其中(x,y)表示x,y的最大公约数。求符合这个条件的三元组的个数。
  限制:
  3 <= n <= 1e5; 1 <= ai <= 1e5
  思路:
  设bi为与ai互质的数的个数,则符合条件 !(((a,b)=(b,c)=(a,c)=1) || ((a,b)!=1 && (b,c)!=1 && (a,c)!=1)) 的三元组的个数为:
  t=(sigma(1~n)bi*(n-1-bi))/2
  可以看到C(n,3)-t即为答案。
  下面证明上面式子的由来:
  对于任意符合条件的a,b,c有以下6种情况:
  1. (a,b)=1 && (a,c)!=1 && (b,c)=1
  2. (a,b)=1 && (a,c)!=1 && (b,c)!=1
  3. (a,b)!=1 && (a,c)=1 && (b,c)=1
  4. (a,b)!=1 && (a,c)=1 && (b,c)!=1
  5. (a,b)=1 && (a,c)=1 && (b,c)!=1
  6. (a,b)!=1 && (a,c)!=1 && (b,c)=1
  我们可以发现bi*(n-1-bi)只覆盖了上面的1~4的情况,但我们又发现剩下两种情况可以由b或c来覆盖
  其实对于1~6的情况,每种情况都被覆盖了两遍
  1. 被a,c覆盖
  2. 被a,b覆盖
  ...
  所以是所有的加起来/2

  然后问题就被化简为对于每个数,在复杂度内求和它互质的数的个数,这个可以用容斥做,也可以用莫比乌斯反演来做
  对于一个给定的数x0
  设f(k)为gcd(x0,x)=k的x的数目
  设F(k)为gcd(x0,x)为k的倍数的x的数目,然后发现F(k)为拥有因子k的ai的数目,这个可以用O(sqrt(ai))枚举因子预处理出来。
 */
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       
#include
       
       
        
        
#include
        
        
          using namespace std; #define LL __int64 #define PB push_back const int N=1e5+5; vector 
         
           fac[N]; int tab[N]; int cnt[N]; int mu[N]; //O(nlog(n)) void getMu(){ for(int i=1;i 
           
          
        
       
       
      
      
     
     
    
    


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值