BZOJ 3994: [SDOI2015]约数个数和|莫比乌斯反演

本文探讨了一种使用数学公式解决复杂计算问题的方法,并通过实例展示了如何将数学原理应用于实际编程场景中,使得计算效率得到了显著提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有一个非常神的东西:

d(nm)=i|nj|mgcd(i,j)==1

并不知道怎么证明……然后有了这个式子后面就很简单了!
然后
Ans=i=1nj=1mnimj(gcd(i,j)==1)

=i=1nj=1md|i,d|ju(d)nimj

=d=1minn,m)u(d)i=1ndj=1mdndimdj

=d=1minn,m)u(d)(i=1ndndij=1mdmdj)

=d=1minn,m)u(d)f(nd)f(md)

然后可以发现f(x)即为d(x)的前缀和,d(x)可以线性筛出来
(当年参加省选,这个题打表就有20分……我感觉暴力第一个点就会超时然后就弃疗了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define ll  long long
#define N 50050
#define mx 1e9
using namespace std;
int sc()
{
    int i=0,f=1; char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
    return i*f;
}
int a[N],prime[N];
int mu[N],d[N],low[N];
void pre()
{
    int top=0;
    mu[1]=low[1]=d[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!a[i])
        {
            low[i]=prime[++top]=i;
            d[i]=2;mu[i]=-1;
        }
        for(int j=1;prime[j]*i<N;j++)
        {
            a[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                low[i*prime[j]]=low[i]*prime[j];
                if(low[i]==i)
                    d[i*prime[j]]=d[i]+1;
                else
                    d[i*prime[j]]=d[i/low[i]]*d[prime[j]*low[i]];
                break;
            }
            low[i*prime[j]]=prime[j];
            d[i*prime[j]]=d[i]*2;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=2;i<N;i++)mu[i]+=mu[i-1],d[i]+=d[i-1];
}   
long long solve(int n,int m)
{
    long long ans=0;
    if(n>m)swap(n,m);
    for(int i=1,last;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans+=(ll)(mu[last]-mu[i-1])*d[n/i]*d[m/i];
    }
    return ans;
}
int main()
{
    pre();
    int T=sc();
    while(T--)
    {
        int x=sc(),y=sc();
        printf("%lld\n",solve(x,y));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值