$HDU$1695 莫比乌斯反演

正解:莫比乌斯反演

解题报告:

传送门!

这题是,莫比乌斯反演的板子,,,所以没什么好说的,只大概记录一下基操,具体学习笔记什么的,,,我大概以后会写$QAQ$?(,,,我最近越来越懒了鸽了好多学习笔记昂1551

首先因为是英文所以先翻译一个题意,,,大概就是,给定abcdk,然后求对于$x\in [a,b],y\in [c,d]$,有多少数对满足$gcd(x,y)=k$

然后保证$a$=$c$=1(,,,所以为什么要给定$a,c$昂,,,有猫病QAQ?

首先考虑到如果只是要求$gcd(x,y)$是$k$的倍数,就很好求嘛,就只要$xy$都是$k$的倍数就好,所以设$F(x)$表示$gcd$是$k$的倍数的数对数量,显然有$F(x)=⌊b/x⌋\cdot ⌊a/x⌋$

然后再设$f(x)$表示我们要的答案,也就是$gcd(x,y)=k$的数对数量,显然$F(x)=\sum f(d)$,其中$x|d$,这显然就转化成了莫比乌斯反演的性质?就是$f(x)=\mu (d/x)*F(d)$

然后这样还是有点儿不好做,所以可以考虑,再转化一下,显然gcd(x,y)=k能转化成gcd(x/k,y/k)=1

所以题目就变成了,求$f(1)$,其中要求$x\in [a,\frac{b}{k}],y\in [c,\frac{d}{k}]$

考虑关于$xy$的要求怎么转化?就显然是$F(d)$的那个$d=\frac{min(b,d)}{k}$就好

然后还没有做完,,,看题,说$(x,y)$和$(y,x)$是一样儿的

所以考虑去重,把重复的删去

然后就做完辣?

具体关于怎么求莫比乌斯函数以及这个$f(x)$的表达式之类的这篇博客里都不会有的,,,如果我有时间写莫比乌斯反演学习笔记的时候再说趴$QAQ$

$HDU$1695 莫比乌斯反演$HDU$1695 莫比乌斯反演
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rc register char
#define rb register bool
#define rp(i,x,y) for(ri i=x;i<=y;++i)

const int N=1e5+10;
int a,b,c,d,k,as1,as2,lim,miu[N],prim[N],pr_cnt;
bool isprim[N];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void pre()
{
    miu[1]=1;
    rp(i,2,N-10)
    {
        if(!isprim[i])prim[++pr_cnt]=i,miu[i]=-1;
        rp(j,1,pr_cnt)
        {
            if(prim[j]*i>N)break;
            isprim[prim[j]*i]=1;if(!(i%prim[j]))miu[prim[j]*i]=0;else miu[prim[j]*i]-=miu[i];
        }
    }
}

main()
{
    int T=read();pre();
//    rp(i,1,20)printf("i=%lld miu=%lld\n",i,miu[i]);
    rp(i,1,T)
    {
        printf("Case %lld: ",i);
        a=read();b=read();c=read();d=read();k=read();as1=as2=0;
        if(!k){printf("0\n");continue;}
        b/=k;d/=k;lim=min(b,d);
        rp(i,1,lim)as1+=1ll*miu[i]*(b/i)*(d/i);
        rp(i,1,lim)as2+=1ll*miu[i]*(lim/i)*(lim/i);
        printf("%lld\n",as1-as2/2);
    }
    return 0;
}
放个代码QAQ