BZOJ3561 DZY Loves Math VI【莫比乌斯反演】

Time Limit: 10 Sec
Memory Limit: 256 MB

Description

给定正整数n,m。求
在这里插入图片描述

Input

一行两个整数n,m

Output

一个整数,为答案模1000000007后的值

HINT

1<=n,m<=500000,共有3组数据


题目分析

和 洛谷P1829 [国家集训队]Crash的数字表格的推导过程很像

∑ i = 1 n ∑ j = 1 m l c m ( i , j ) g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 m ( i j g c d ( i , j ) ) g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^mlcm(i,j)^{gcd(i,j)}=\sum_{i=1}^n\sum_{j=1}^m(\frac{ij}{gcd(i,j)})^{gcd(i,j)} i=1nj=1mlcm(i,j)gcd(i,j)=i=1nj=1m(gcd(i,j)ij)gcd(i,j)

把gcd提出来枚举

∑ d = 1 m i n ( n , m ) ∑ i = 1 n ∑ j = 1 m ( i j d ) d [ g c d ( i , j ) = d ] \sum_{d=1}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m(\frac{ij}{d})^{d}[gcd(i,j)=d] d=1min(n,m)i=1nj=1m(dij)d[gcd(i,j)=d]

g c d ( i , j ) = = d gcd(i,j)==d gcd(i,j)==d,则有 g c d ( i / d , j / d ) = 1 gcd(i/d,j/d)=1 gcd(i/d,j/d)=1

∑ d = 1 m i n ( n , m ) ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x d ∗ y d d ) d [ g c d ( x , y ) = 1 ] = ∑ d = 1 m i n ( n , m ) d d ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d [ g c d ( x , y ) = 1 ] \sum_{d=1}^{min(n,m)}\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(\frac{xd*yd}{d})^{d}[gcd(x,y)=1]=\sum_{d=1}^{min(n,m)}d^d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}[gcd(x,y)=1] d=1min(n,m)x=1dny=1dm(dxdyd)d[gcd(x,y)=1]=d=1min(n,m)ddx=1dny=1dm(xy)d[gcd(x,y)=1]

莫比乌斯反演一下

∑ d = 1 m i n ( n , m ) d d ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d ∑ z ∣ g c d ( x , y ) μ ( z ) = ∑ d = 1 m i n ( n , m ) d d ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d ∑ z = 1 g c d ( x , y ) μ ( z ) [ z ∣ g c d ( x , y ) ] \sum_{d=1}^{min(n,m)}d^d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}\sum_{z|gcd(x,y)}\mu(z)=\sum_{d=1}^{min(n,m)}d^d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}\sum_{z=1}^{gcd(x,y)}\mu(z)[z|gcd(x,y)] d=1min(n,m)ddx=1dny=1dm(xy)dzgcd(x,y)μ(z)=d=1min(n,m)ddx=1dny=1dm(xy)dz=1gcd(x,y)μ(z)[zgcd(x,y)]

变换一下枚举顺序
∑ d = 1 m i n ( n , m ) d d ∑ z = 1 m i n ( ⌊ n d ⌋ , ⌊ m d ⌋ ) μ ( z ) ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d [ z ∣ g c d ( x , y ) ] \sum_{d=1}^{min(n,m)}d^d\sum_{z=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\mu(z)\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}[z|gcd(x,y)] d=1min(n,m)ddz=1min(dn,dm)μ(z)x=1dny=1dm(xy)d[zgcd(x,y)]
x , y x,y x,y的枚举替换成枚举 z z z的倍数
∑ d = 1 m i n ( n , m ) d d ∑ z = 1 m i n ( ⌊ n d ⌋ , ⌊ m d ⌋ ) μ ( z ) ∑ t 1 = 1 ⌊ n d z ⌋ ∑ t 2 = 1 ⌊ m d z ⌋ ( z 2 t 1 t 2 ) d = ∑ d = 1 m i n ( n , m ) d d ∑ z = 1 m i n ( ⌊ n d ⌋ , ⌊ m d ⌋ ) z 2 d μ ( z ) ∑ t 1 = 1 ⌊ n d z ⌋ t 1 d ∑ t 2 = 1 ⌊ m d z ⌋ t 2 d \sum_{d=1}^{min(n,m)}d^d\sum_{z=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\mu(z)\sum_{t_1=1}^{\lfloor\frac{n}{dz}\rfloor}\sum_{t_2=1}^{\lfloor\frac{m}{dz}\rfloor}(z^2t_1t_2)^{d}=\sum_{d=1}^{min(n,m)}d^d\sum_{z=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}z^{2d}\mu(z)\sum_{t_1=1}^{\lfloor\frac{n}{dz}\rfloor}t_1^d\sum_{t_2=1}^{\lfloor\frac{m}{dz}\rfloor}t_2^{d} d=1min(n,m)ddz=1min(dn,dm)μ(z)t1=1dznt2=1dzm(z2t1t2)d=d=1min(n,m)ddz=1min(dn,dm)z2dμ(z)t1=1dznt1dt2=1dzmt2d

虽然由于每一项几乎都有d次幂不方便维护前缀和
但认真观察发现最后那两个和式每次从上一次d-1次幂继承,只用 O ( m / d ) O(m/d) O(m/d)处理
z 2 d μ ( z ) z^{2d}\mu(z) z2dμ(z)需要 O ( n / d ∗ l o g d ) O(n/d*logd) O(n/dlogd)处理
总复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)级的

由于每个测试点只有一组数据,完全可以接受


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x))
 
int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}
 
const int mod=1000000007;
const int maxn=500010;
int T;
int miu[maxn];
int prim[maxn],vis[maxn],cnt;
lt sum[maxn],a[maxn];
 
lt qpow(lt a,int k)
{
    lt res=1;
    while(k>0){
        if(k&1) res=(res*a)%mod;
        a=(a*a)%mod; k>>=1;
    }
    return res;
}
 
void Miu(int n)
{
    miu[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!vis[i]) prim[++cnt]=i,miu[i]=-1;
        for(int j=1;j<=cnt;++j)
        {
            if(i*prim[j]>n) break;
            vis[i*prim[j]]=1;
            if(i%prim[j]==0) break;
            else miu[i*prim[j]]=-miu[i];
        }
    }
}
 
lt query(int n,int m)
{
    lt res=0; if(n>m) swap(n,m);
    for(int i=1;i<=m;++i) a[i]=1;
     
    for(int d=1;d<=n;++d)
    {
        for(lt i=1;i<=m/d;++i)
        {
            a[i]=a[i]*i%mod;
            sum[i]=(sum[i-1]+a[i])%mod;
        }
         
        lt tt=0;
        for(int j=1;j<=n/d;++j)
        {
            tt+=(qpow(j,2*d)*miu[j]%mod+mod)%mod * sum[n/(j*d)]%mod * sum[m/(j*d)]%mod;
            tt%=mod;
        }
         
        res+=qpow(d,d)*tt%mod; 
        res%=mod;
    }
    return res;
}
 
int main() 
{
    int n=read(),m=read();
    Miu(min(n,m));
    printf("%lld",query(n,m));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值