zoukankan      html  css  js  c++  java
  • HDU 6053 TrickGCD(莫比乌斯反演)

    http://acm.hdu.edu.cn/showproblem.php?pid=6053

    题意:
    给出一个A数组,B数组满足Bi<=Ai。

    现在要使得这个B数组的GCD值>=2,求共有多少种情况。

    思路:
    在比赛的时候筛了素数表,然后枚举GCD来做,但是还是有些重复情况无办法剔除,赛后才知道是要用莫比乌斯来处理的,然后就趁机学习了一下莫比乌斯。

    先是枚举GCD,每个数的可选情况就是GCD/a【i】,在这里我们可以把GCD/a【i】相同的数一起处理,也就是用快速幂来计算,这样会显得更快。

    那么莫比乌斯是用来干嘛的呢?

    然后就是容斥思想。

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<sstream>
      6 #include<vector>
      7 #include<stack>
      8 #include<queue>
      9 #include<cmath>
     10 #include<map>
     11 #include<set>
     12 using namespace std;
     13 typedef long long ll;
     14 typedef pair<int,int> pll;
     15 const int INF = 0x3f3f3f3f;
     16 const int maxn = 1e5 + 5;
     17 
     18 const int mod= 1e9+7;
     19 
     20 int n;
     21 int a[maxn];
     22 
     23 ll cnt[maxn];
     24 ll num[3*maxn];
     25 
     26 bool check[maxn+1000];
     27 int prime[maxn+1000];
     28 int mu[maxn+1000];
     29 
     30 void Moblus()
     31 {
     32     memset(check,false,sizeof(check));
     33     mu[1] = 1;
     34     int tot = 0;
     35     for(int i = 2; i <= maxn; i++)
     36     {
     37         if( !check[i] ){
     38             prime[tot++] = i;
     39             mu[i] = -1;
     40         }
     41         for(int j = 0; j < tot; j++)
     42         {
     43             if(i * prime[j] > maxn) break;
     44             check[i * prime[j]] = true;
     45             if( i % prime[j] == 0){
     46                 mu[i * prime[j]] = 0;
     47                 break;
     48             }else{
     49                 mu[i * prime[j]] = -mu[i];
     50             }
     51         }
     52     }
     53 }
     54 
     55 ll qpow(ll a, ll b)
     56 {
     57     ll ans=1;
     58     while(b)
     59     {
     60         if(b&1)  ans=(ans*a)%mod;
     61         a=(a*a)%mod;
     62         b>>=1;
     63     }
     64     return ans;
     65 }
     66 
     67 int main()
     68 {
     69     //freopen("in.txt","r",stdin);
     70     Moblus();
     71     int kase=0;
     72     int T;
     73     scanf("%d",&T);
     74     while(T--)
     75     {
     76         memset(cnt,0,sizeof(cnt));
     77         scanf("%d",&n);
     78         int MIN=INF;
     79         int MAX=0;
     80         for(int i=1;i<=n;i++)
     81         {
     82             scanf("%d",&a[i]);
     83             MIN=min(MIN,a[i]);
     84             MAX=max(MAX,a[i]);
     85             cnt[a[i]]++;
     86         }
     87 
     88         num[0]=0;
     89         for(int i=1;i<=200000;i++)   num[i]=num[i-1]+cnt[i];
     90 
     91         ll ans=0;
     92 
     93         for(int i=2;i<=MIN;i++)
     94         {
     95             ll tmp=1;
     96             for(int j=1;j*i<=MAX;j++)
     97             {
     98                 tmp=(tmp*qpow((ll)j,num[i*j+i-1]-num[i*j-1]))%mod;  //快速幂计算,j是GCD的倍数,也就是a【i】/GCD
     99             } 
    100             ans=(ans-tmp*mu[i]+mod)%mod;  
    101         }
    102 
    103         printf("Case #%d: %I64d
    ",++kase,ans);
    104     }
    105     return 0;
    106 }
  • 相关阅读:
    windowssdk编程从简单的对话框开始
    面向扣扣编程知识一
    循序渐进DLL编程(二)
    西方经济学导论
    循序渐进DLL编程(五)
    HLSL Effect的vertex shader和pixel shader的参数传递
    Directx11 HelloWorld之与Directx9的比较
    Directx11 HelloWorld之简单三角形绘制
    正式开始记录自己学习历程
    坐标系的转换
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7248239.html
Copyright © 2011-2022 走看看