[SDOI2015]约数个数和

一、题目

点此看题

二、解法

首先证明一个结论:
d ( i , j ) = ∑ x ∣ i ∑ y ∣ j [ gcd ⁡ ( x , y ) = 1 ] d(i,j)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] d(i,j)=xiyj[gcd(x,y)=1]证明考虑单个质因数 p p p,设 i i i中有 p a p^a pa j j j中有 p b p^b pb,等式右边的贡献是 a + b + 1 a+b+1 a+b+1,等式左边考虑 x x x中没有 p p p,贡献为 b b b y y y中没有 p p p,贡献为 a a a x , y x,y x,y都没有 p p p,贡献为 1 1 1,总贡献也是 a + b + 1 a+b+1 a+b+1,等式右边的每个质因数互相独立,可以理解为枚举了所有情况相当于所有贡献的乘积,证毕。


现在用上面的结论来推式子:
∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j [ gcd ⁡ ( x , y ) = 1 ] \sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] i=1nj=1mxiyj[gcd(x,y)=1]我们枚举 x , y x,y x,y,这样 i , j i,j i,j的取值我们就知道了:
∑ x = 1 n ∑ y = 1 m n x × m y [ gcd ⁡ ( x , y ) = 1 ] \sum_{x=1}^n\sum_{y=1}^m \frac{n}{x}\times\frac{m}{y}[\gcd(x,y)=1] x=1ny=1mxn×ym[gcd(x,y)=1] gcd ⁡ \gcd gcd是很容易反演的,搞一波莫比乌斯反演:
f ( i ) = ∑ x = 1 n ∑ y = 1 m n x × m y [ gcd ⁡ ( x , y ) = i ] f(i)=\sum_{x=1}^n\sum_{y=1}^m \frac{n}{x}\times\frac{m}{y}[\gcd(x,y)=i] f(i)=x=1ny=1mxn×ym[gcd(x,y)=i] F ( i ) = ∑ x = 1 n ∑ y = 1 m n x × m y [ i ∣ gcd ⁡ ( x , y ) ] = ∑ i ∣ d f ( d ) F(i)=\sum_{x=1}^n\sum_{y=1}^m \frac{n}{x}\times\frac{m}{y}[i|\gcd(x,y)]=\sum_{i|d}f(d) F(i)=x=1ny=1mxn×ym[igcd(x,y)]=idf(d) f ( i ) = ∑ i ∣ d μ ( d i ) F ( d ) f(i)=\sum_{i|d}\mu(\frac{d}{i})F(d) f(i)=idμ(id)F(d)我们要求的是 f ( 1 ) f(1) f(1)
f ( 1 ) = ∑ i = 1 n μ ( i ) F ( i ) f(1)=\sum_{i=1}^n\mu(i)F(i) f(1)=i=1nμ(i)F(i)问题变成了如何求 F ( i ) F(i) F(i),继续推式子,考虑消去 gcd ⁡ \gcd gcd的影响:
F ( i ) = ∑ x = 1 n / i ∑ y = 1 m / i n x i m y i F(i)=\sum_{x=1}^{n/i}\sum_{y=1}^{m/i}\frac{n}{xi}\frac{m}{yi} F(i)=x=1n/iy=1m/ixinyim只要我们知道了 s ( x ) = ∑ i = 1 x x i s(x)=\sum_{i=1}^x \frac{x}{i} s(x)=i=1xix,那么 F ( i ) F(i) F(i)也就迎刃而解了, s ( i ) s(i) s(i)是可以通过分块 O ( n n ) O(n\sqrt n) O(nn )预处理的,至于询问也可以用分块解决,时间复杂度 O ( T n ) O(T\sqrt n) O(Tn ),贴个代码 q w q qwq qwq

#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
const int M = 50005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int T,n,m,cnt,p[M],vis[M],mu[M],s[M];
void init(int n)
{
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            p[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cnt && i*p[j]<=n;j++)
        {
            vis[i*p[j]]=1;
            if(i%p[j]==0) break;
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)
    {
        mu[i]+=mu[i-1];
        for(int l=1,r;l<=i;l=r+1)
        {
            r=i/(i/l);
            s[i]+=(r-l+1)*(i/l);
        }
    }
}
signed main()
{
    T=read();
    init(5e4);
    while(T--)
    {
        n=read();m=read();
        if(n>m) swap(n,m);
        int ans=0;
        for(int l=1,r;l<=n;l=r+1)
        {
            r=min(n/(n/l),m/(m/l));
            ans+=(mu[r]-mu[l-1])*s[n/l]*s[m/l];
        }
        printf("%lld\n",ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值