• Gym


    题目链接:http://codeforces.com/gym/101982/attachments

    题目大意:有区间[a,b]和区间[c,d],求gcd(x,y)=1,其中x属于[a,b],y属于[c,d],求这样的x,y有多少对。

    解题思路:

    第一种反演思路:

    把下界变换一下

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int maxn=1e7+7;
    ll a,b,c,d,mu[maxn],sum[maxn],prime[maxn],tot;
    void getMobius(int N){
        for(int i=1;i<=N;i++) prime[i]=1;
        mu[1]=1;
        tot=0;
        for(int i=2;i<=N;i++){
            if(prime[i]){
                prime[tot++]=i;
                mu[i]=-1;
            }
            for(int j=0;j<tot&&prime[j]*i<=N;j++){
                prime[prime[j]*i]=0;
                if(i%prime[j]==0){
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
    int main()
    {
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        getMobius(1e7);
        ll ans=0;
        for(int i=1;i<=min(b,d);i++)
            ans+=mu[i]*(b/i-(a-1)/i)*(d/i-(c-1)/i);
        printf("%lld
    ",ans);
        return 0;
    }

    第二种反演思路:

    右边全部都是已知的,枚举下可取范围内的d(也就是原来n的倍数,这里n是1)

    可以利用容斥原理,先求出[1,b]和[1,d],再减去[1,a-1]和[1,d]以及[1,b]和[1,c-1],最后加上多减的部分[1,a-1]和[1,c-1]。

    并且很显然,推演最后得到的式子是可以经过整除分块优化的,只需要预处理出莫比乌斯函数的前缀和即可。

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int maxn=1e7+7;
    ll a,b,c,d,mu[maxn],sum[maxn],prime[maxn],tot;
    void getMobius(int N){
        for(int i=1;i<=N;i++) prime[i]=1;
        mu[1]=1;
        tot=0;
        for(int i=2;i<=N;i++){
            if(prime[i]){
                prime[tot++]=i;
                mu[i]=-1;
            }
            for(int j=0;j<tot&&prime[j]*i<=N;j++){
                prime[prime[j]*i]=0;
                if(i%prime[j]==0){
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
    ll solve(ll n,ll m){
        ll res=0;
        for(ll l=1,r=0;l<=min(n,m);l=r+1){
            r=min(n/(n/l),m/(m/l));
            res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
        }
        return res;
    }
    int main()
    {
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        getMobius(1e7);
        sum[1]=1;
        for(int i=2;i<=1e7;i++) sum[i]=sum[i-1]+mu[i];
        printf("%lld
    ",solve(b,d)-solve(a-1,d)-solve(c-1,b)+solve(a-1,c-1));
        return 0;
    }
  • 相关阅读:
    20165309 Linux安装及学习
    20165309 技能学习经验与C语言
    20165309 我期望的师生关系
    20165317-我期望的师生关系
    20165308 学习基础和C语言基础调查
    20165308 我期望的师生关系
    20165320 结对编程学习第一周
    20165320 第七周学习总结
    20165320 第六周学习总结
    20165320 实验一 java环境的熟悉
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/10789534.html
Copyright © 2020-2023  润新知