• BZOJ 2301 莫比乌斯反演入门


    2301: [HAOI2011]Problem b

    Description

    对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
     

    Input

    第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

    Output

    共n行,每行一个整数表示满足要求的数对(x,y)的个数

    Sample Input

    2
    2 5 1 5 1
    1 5 1 5 2
     
    Sample Output
    14
    3
    此题作为我的莫比乌斯反演的入门题
    推荐文章 
        https://wenku.baidu.com/view/fbec9c63ba1aa8114431d9ac.html      学习莫比乌斯反演
        https://wenku.baidu.com/view/fbe263d384254b35eefd34eb.html
           http://blog.csdn.net/outer_form/article/details/50590197
    简单的说下莫比乌斯反演的作用
      对于一个函数f(n) 我们很难直接求出它的值,但是我可以求出倍数和或者约束和F(n),那么我们就可以将F通过莫比乌斯反演来得到f,基于容斥思想
      莫比乌斯反演常用于处理一些gcd的问题
    代码如下:
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef long long LL;
    const int maxn = 5e4+5000;
    int p[maxn],mo[maxn],phi[maxn],cnt,sum[maxn];
    int a,b,c,d,k;
    bool vis[maxn];
    void init()
    {
        mo[1]=1;
        phi[1]=1;
        for(int i=2;i<=maxn-10;i++){
            if(!vis[i]){
                mo[i]=-1;
                phi[i]=i-1;
                p[cnt++]=i;
            }
            for(int j=0;j<cnt&&(ll)i*p[j]<=maxn-10;j++){
                vis[i*p[j]]=true;
                if(i%p[j]==0){
                    mo[i*p[j]]=0;
                    phi[i*p[j]]=phi[i]*p[j];
                    break;
                }
                mo[i*p[j]]=-mo[i];
                phi[i*p[j]]=phi[i]*(p[j]-1);
            }
        }
    }
    ll solve (int n,int m)
    {
        ll ret =  0;
        if (n>m) swap(n,m);
        for (int i=1,la=0;i<=n;i=la+1){
            la = min(n/(n/i),m/(m/i));
            ret+=(long long)(sum[la]-sum[i-1])*(n/i)*(m/i);
        }
        return ret;
    }
    int main()
    {
        //freopen("de.txt","r",stdin);
        init();
        int T;
        for (int i=1;i<=50000;++i) sum[i] = sum[i-1] + mo[i];
        scanf("%d",&T);
        while (T--){
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
            ll ans = solve(b/k,d/k)-solve((a-1)/k,d/k)-solve((c-1)/k,b/k)+solve((a-1)/k,(c-1)/k);
            printf("%lld
    ",ans);
        }
        return 0;
    }
     
  • 相关阅读:
    博客的开端,找对象不再new
    OpenGL编程 基础篇(六)OpenGL中几种光照参数
    OpenGL编程 基础篇(五)世界窗口和视口
    百练2952:循环数
    百练2811:熄灯问题
    百练2812:恼人的青蛙
    百练3177:判决素数个数
    百练1248:Safecracker
    OpenGL编程 基础篇(四)与鼠标的交互
    OpenGL编程 基础篇(三)用点集绘制函数
  • 原文地址:https://www.cnblogs.com/agenthtb/p/7299629.html
Copyright © 2020-2023  润新知