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

    题意略。

    思路:首先想到暴力去扫,这样的复杂度是n * min(ai),对于gcd = p,对答案的贡献应该是 (a1 / p) * (a2 / p) * .... * (an / p),得出这个贡献未必要暴力地去扫,

    我们可以分桶后,再求后缀和,再作差来得到个数后,进行快速幂。比如说:我们想知道gcd = p时对答案的贡献,那么add = (c1 ^ d1) * (c2 ^ d2) *.....,其中

    c1是ai / p之后得出的数,d1表示(a1 / p) * (a2 / p) * .... * (an / p)中,有多少ai / p == c1,这样我们求出所有的ci所用时间是 log(n) ,对于每一个ci,要求出

    ci ^ di所用时间也是log的。把每一个 <= min(ai)统计一次,所用时间是n * logn * logn。

    注意,我们在枚举p的时候,只枚举由互不相同的因子组成的p,当p内含有相同因子时,它是前种情况的子集,这里肯定有重复,可以利用莫比乌斯反演来

    去重。

    详见代码:

    #include<bits/stdc++.h>
    #define maxn 100005
    //#define LOCAL
    using namespace std;
    typedef long long LL;
    const LL mod = 1e9 + 7;
    
    bool check[maxn];
    int prime[maxn],mu[maxn];
    LL sum[maxn];
    
    void mobius(){
        memset(check,false,sizeof(check));
        mu[1] = 1;
        int tot = 0;
        for(int i = 2;i < maxn;++i){
            if(!check[i]){
                prime[tot++] = i;
                mu[i] = -1;
            }
            for(int j = 0;j < tot;++j){
                if(i * prime[j] > maxn) break;
                check[i * prime[j]] = true;
                if(i % prime[j] == 0){
                    mu[i * prime[j]] = 0;
                    break;
                }
                else mu[i * prime[j]] = -mu[i];
            }
        }
    }
    LL quick_pow(LL a,LL n){
        LL ret = 1;
        while(n > 0){
            if(n & 1){
                ret *= a;
                ret %= mod;
            }
            n = n / 2;
            a = a * a % mod;
        }
        return ret;
    }
    
    int main(){
        #ifdef LOCAL
        freopen("kkk.txt","r",stdin);
        freopen("kkkout.txt","w",stdout);
        #endif
        int T,cas = 1;
        mobius();
        scanf("%d",&T);
        while(T--){
            int minn = maxn,maxx = -maxn;
            int n,temp;
            scanf("%d",&n);
            memset(sum,0,sizeof(sum));
            for(int i = 0;i < n;++i){
                scanf("%d",&temp);
                ++sum[temp];
                minn = min(minn,temp);
                maxx = max(maxx,temp);
            }
            for(int i = maxn - 2;i >= 0;--i)
                sum[i] += sum[i + 1];
            LL ans = 0;
            for(int i = 2;i <= minn;++i){
                if(mu[i] == 0) continue;
                LL temp = -mu[i];
                for(int j = i;j <= maxx;j += i){
                    temp = (temp * quick_pow(j / i,sum[j] - sum[min(maxx + 1,j + i)]) % mod);
                }
                ans += temp;
                ans = (ans % mod + mod) % mod;
            }
            printf("Case #%d: %lld
    ",cas++,ans);
        }
        return 0;
    }
    
    /*
    1
    4
    4 6 9 7
    */
  • 相关阅读:
    AD预测论文研读系列2
    hdu 5795
    sg函数的应用
    二分查找
    快速幂
    筛选法素数打表
    多校hdu-5775 Bubble sort(线段树)
    多校hdu5754(博弈)
    多校hdu5738 寻找
    多校hdu5726 线段树+预处理
  • 原文地址:https://www.cnblogs.com/tiberius/p/8612465.html
Copyright © 2011-2022 走看看