• [BZOJ 2301] Problem B


    Link:

    https://www.lydsy.com/JudgeOnline/problem.php?id=2301

    Algorithm: 

    令$g(n,m)$表示在$1<=x<=n,1<=y<=m$满足$gcd(x,y)$是$k$的$(x,y)$的对数。

    那么由容斥原理可得$ans=g(b,d)+g(a−1,c-1)−g(a-1,d)-g(b,c−1,k)$

    满足$gcd(x,y)$是$k$的$(x,y)$的对数也等价于$(x,y)$互质的对数($1le xle n/k,1le yle m/k$),即

     $g(n,m,k)=g(n/k,m/k,1)$

    令$f(i)$表示满足$gcd(x,y)=i$时$(x,y)$的对数

     $F(i)$表示满足$i|gcd(x,y)的(x,y)$的对数,则$F(i)=lfloor n_i floor lfloor m_i floor$。

    于是我们发现这是一个具有倍数关系的莫比乌斯反演:

    $F(i)=sum_{i | d} f(d)$    <->     $f(i)=sum_{i|d} miu(d/i)*(n/d)*(m/d)$

    接下来就要优化每次求f(i)的复杂度,需要将其降至$O(logN)$,

    发现$[n/d]$最多有$2sqrt(n)$个取值,那么 $(n/d)*(m/d)$就至多有$2sqrt(n)+2sqrt(m)$个取值

     (并不是$*$,对于每个$d in n/(sqrt(n)+1)<dle n $, $(n/d)*(m/d)$仍只有一个值)

    于是我们发现会有连续的一段$(n/d)*(m/d)$的值相同,便可以使用分块来优化

    注意其中转移到下一块的处理技巧:$i=x/(x/i)+1$

    个人认为$x/(x/i)$表示根据当前$x/i$的值找出最大的$i′$,再加一就是另一个$x/i$值了

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=5e4+10;
    inline ll read()
    {
        char ch;ll num,f=0;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    
    int a,b,c,d,k;
    int sum[MAXN],mo[MAXN],pri[MAXN],cnt;
    bool mark[MAXN];
    void getmo()
    {
        mo[1]=1;
        for(int i=2;i<=5e4;i++)
        {
            if(!mark[i]){mo[i]=-1;pri[++cnt]=i;}
            for(int j=1;j<=cnt && i*pri[j]<=5e4;j++)
            {
                mark[i*pri[j]]=1;
                if(i%pri[j]==0){mo[i*pri[j]]=0;break;}
                else mo[i*pri[j]]=-mo[i];
            }
        }
        for(int i=1;i<=5e4;i++)
            sum[i]=sum[i-1]+mo[i];
    }
    int cal(int n,int m)
    {
        n/=k;m/=k;
        if(n>m)swap(n,m);
        int ret=0,pos;
        for(int i=1;i<=n;i=pos+1)
        {
            pos=min(n/(n/i),m/(m/i));
            ret+=(sum[pos]-sum[i-1])*(n/i)*(m/i);
        }
        return ret;
    }
    int main()
    {
        getmo();
        int T=read();
        while(T--)
        {
            a=read();b=read();c=read();d=read();k=read();
            int res=cal(a-1,c-1)+cal(b,d)-cal(a-1,d)-cal(b,c-1);
            printf("%d
    ",res);
        }
        return 0;
    }

     Review:

    1、 将gcd(x,y)=k这样的条件转化为x/k与y/k互质

          方便使用欧拉函数或莫比乌斯反演解题

     

    2、使用分块对莫比乌斯反演的优化

  • 相关阅读:
    你不知道的JavaScript(上)作用域与闭包
    csu 1982: 小M的移动硬盘
    csu 1985: 驱R符
    csu 1987: 绚丽的手链
    2017ACM/ICPC广西邀请赛 1007 Duizi and Shunzi
    2017ACM/ICPC广西邀请赛 1005 CS Course
    2017ACM/ICPC广西邀请赛 1004 Covering
    hdu 1209 Clock
    trac中wiki直接显示任务代码
    phpcms中action值的含义
  • 原文地址:https://www.cnblogs.com/newera/p/9077511.html
Copyright © 2020-2023  润新知