• hdu 1695 GCD 莫比乌斯反演入门


    GCD

    题意:输入5个数a,b,c,d,k;(a = c = 1, 0 < b,d,k <= 100000);问有多少对a <= p <= b, c <= q <= d使得gcd(p,q) = k;

    注:对于(p,q)和(q,p)只算一次;

    思路:由于遍历朴素求两个数的gcd的时间复杂度为O(n^2*log(n)),朴素算法遍历搜索在判断累加,所以效率很低;

    资料   NanoApe's Blog   ACdreamers

    莫比乌斯反演:利用整与分之间的可逆来由整体利用容斥原理得到分量的值;这就是用容易求解的F[n]通过莫比乌斯公式(函数mu[])得到分量f[n]的值;

    如本题中:F[n]表示公倍数是n的倍数的个数,f[n]表示公倍数为n的个数;即F[d] = Σf[n] ,(d|n);

    同样每个F[d](d|n)中都含有f[n]的分量,所以可以使用容斥原理来求解;对应下面两个公式;

    公式1:

    公式2:

    细节:这道题b,d并不相等,由于只是组合不是排列,这需要两次求之后去重;开始直接线性筛法把mu[]预处理出来即可;

    坑:以前线性筛素数,一直用的p[j] < MAXN/i没事,今天各种WA...打击真大。。之后改成p[j]*i < MAXN也没做1LL*处理都没事。。

    时间复杂度为:O(n)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    #include<stack>
    #include<set>
    #include<map>
    #include<queue>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    #define MSi(a) memset(a,0x3f,sizeof(a))
    #define inf 0x3f3f3f3f
    #define lson l, m, rt << 1
    #define rson m+1, r, rt << 1|1
    typedef pair<int,int> PII;
    #define A first
    #define B second
    #define MK make_pair
    typedef __int64 ll;
    template<typename T>
    void read1(T &m)
    {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        m = x*f;
    }
    template<typename T>
    void read2(T &a,T &b){read1(a);read1(b);}
    template<typename T>
    void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
    const int MAXN = 100007;
    int mu[MAXN],vis[MAXN],p[MAXN];
    void mobius()
    {
        mu[1] = 1;//定义
        rep0(i,2,MAXN){
            if(vis[i] == 0){
                mu[i] = -1;
                p[++p[0]] = i;
            }
            for(int j = 1;j <= p[0] && 1LL*p[j]*i < MAXN;j++){ // p[j] < MAXN/i WA了
                vis[i*p[j]] = 1;
                if(i%p[j]) mu[i*p[j]] = -mu[i];
                else{
                    mu[i*p[j]] = 0;
                    break;
                }
            }
        }
    }
    int main()
    {
        int T,kase = 1,a,b,c,d,k;
        mobius();
        read1(T);
        while(T--){
            ll ans = 0,tmp = 0;
            read2(a,b);read3(c,d,k);
            if(k == 0){
                printf("Case %d: %I64d
    ",kase++,ans);
                continue;
            }
            b /= k,d /= k;//**这样更简便
            if(b > d) swap(b,d);
            rep1(i,1,b) ans += 1LL*mu[i]*(b/i)*(d/i);
            rep1(i,1,b) tmp += 1LL*mu[i]*(b/i)*(b/i);
            printf("Case %d: %I64d
    ",kase++,ans - tmp/2);
        }
        return 0;
    }
  • 相关阅读:
    vue学习目录
    充分利用 SQL Server Reporting Services 图表
    MSCRM 用户登录日志
    Microsoft Dynamics CRM MVP
    在SSRS 里实现 SUMIF
    MSCRM 报表显示 rsprocessingaborted 错误
    电商CRM的痛点在哪里?
    MSCRM 2011/2013/2015 修改显示记录数
    MSCRM 2013/2015 Ribbon Editor
    Q:解决每天第一次打开MSCRM系统展示慢的问题
  • 原文地址:https://www.cnblogs.com/hxer/p/5281771.html
Copyright © 2020-2023  润新知