bzoj4659: Lcm(第二次做)

链接

  点击查看题目

思路

上次做这题的时候用了一些玄学水过去了,这次我写了个有理有据的 O(n+TN) O ( n + T N ) 算法,
假设n < m,根据题意写出

ans=i=1nj=1mij(i,j)μ2((i,j)) a n s = ∑ i = 1 n ∑ j = 1 m i j ( i , j ) μ 2 ( ( i , j ) )

=d=1ndμ2(d)i=1ndj=1mdij[(i,j)=1] = ∑ d = 1 n d μ 2 ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j [ ( i , j ) = 1 ]

=d=1ndμ2(d)i=1ndj=1mdijx|(i,j)μ(x) = ∑ d = 1 n d μ 2 ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j ∑ x | ( i , j ) μ ( x )

=d=1ndμ2(d)x=1ndμ(x)x|indx|jmdij = ∑ d = 1 n d μ 2 ( d ) ∑ x = 1 ⌊ n d ⌋ μ ( x ) ∑ x | i ⌊ n d ⌋ ∑ x | j ⌊ m d ⌋ i j

g(x)=xi=1i=x(x+1)2 g ( x ) = ∑ i = 1 x i = x ( x + 1 ) 2
ans=d=1ndμ2(d)x=1ndx2μ(x)g(ndx)g(mdx) a n s = ∑ d = 1 n d μ 2 ( d ) ∑ x = 1 ⌊ n d ⌋ x 2 μ ( x ) g ( ⌊ n d x ⌋ ) g ( ⌊ m d x ⌋ )

这种情况下直接做是 O(TN) O ( T N )
因为每次查询 n n m都在变,因此无法预处理式子后面的那一段,考虑如何把 n n m从后面拿出来,然后再通过预处理一些和 n n m无关的部分来降低每次询问的计算次数
t=dx t = d x
ans=d=1nμ2(d)d|tnt2dμ(td)g(nt)g(mt) a n s = ∑ d = 1 n μ 2 ( d ) ∑ d | t n t 2 d μ ( t d ) g ( ⌊ n t ⌋ ) g ( ⌊ m t ⌋ )

=t=1ng(nt)g(mt)td|ttdμ(td)μ2(d) = ∑ t = 1 n g ( ⌊ n t ⌋ ) g ( ⌊ m t ⌋ ) t ∑ d | t t d μ ( t d ) μ 2 ( d )

这里就看出来了,只要预处理后面那一坨 td|ttdμ(td)μ2(d) t ∑ d | t t d μ ( t d ) μ 2 ( d ) ,每次就可以 O(N) O ( N )
这题最麻烦的就在这里,这个东西要分好几层来看,首先令 f(x)=xμ(x) f ( x ) = x μ ( x ) ,那么上面那一坨就等于 t(fμ2)(t) t ( f ∗ μ 2 ) ( t ) ,其中 是狄利克雷卷积符号。
f(x)肯定是积性函数, μ2(x) μ 2 ( x ) 也是积性函数,因此 (fμ2)(x) ( f ∗ μ 2 ) ( x ) 也是积性函数,外面那个 x x 最后再乘就行。
u(x)=(fμ2)(x)
现在有两种线性筛来求出 u(x) u ( x )
一种是只记录 h(x) h ( x ) ,试图用 h(x) h ( x ) 的值来推导出 h(xpr(x)) h ( x ⋅ p r ( x ) ) ,其中 pr(x) p r ( x ) 是指 x x 的最小质因子,这种只适合于求非完全积性函数和完全积性函数的狄利克雷卷积,这里两个函数都是非完全积性函数的,因此用另一种方法
第二种方法记录每个数的最小质因子pr(x)和最小质因子的幂 p(x) p ( x ) p(x) p ( x ) 的意义是对 x x 不断地除以pr(x),直到无法整除,假设做除法的次数是 q q 那么p(x)=prq(x)。这样可以把一个数分成互质的两部分 xp(x) x p ( x ) p(x) p ( x ) ,则 h(x)=h(xp(x))h(p(x)) h ( x ) = h ( x p ( x ) ) h ( p ( x ) ) ,但是这种方法的缺点是当 p(x)=x p ( x ) = x 时,无法直接求出 h(x) h ( x ) ,必须要根据不同函数的特殊性来推导 h(x) h ( x ) 的值。
p(x)=prq(x) p ( x ) = p r q ( x )
q=2 q = 2 时, h(x)=f(1)μ2(pr2(x))+f(pr(x))μ2(pr(x))+f(pr2(x))μ(1)=pr(x) h ( x ) = f ( 1 ) μ 2 ( p r 2 ( x ) ) + f ( p r ( x ) ) μ 2 ( p r ( x ) ) + f ( p r 2 ( x ) ) μ ( 1 ) = − p r ( x )
q=3 q = 3 时, h(x)=f(1)μ2(pr3(x))++f(pr3(x))μ2(1)=0 h ( x ) = f ( 1 ) μ 2 ( p r 3 ( x ) ) + ⋅ ⋅ ⋅ + f ( p r 3 ( x ) ) μ 2 ( 1 ) = 0
q>3 q > 3 时,同理 h(x)=0 h ( x ) = 0
这样就知道了,当 x=pr2(x) x = p r 2 ( x ) 时, h(x)=pr(x) h ( x ) = − p r ( x ) 而当 x=p(x)>pr2(x) x = p ( x ) > p r 2 ( x ) h(x)=0 h ( x ) = 0
然后就可以线性筛了,总的时间复杂度是 O(N+TN) O ( N + T N )

代码

//线性筛、莫比乌斯反演 
#include <cstdio>
#include <algorithm>
#define maxn 4000010
#define mod 1073741824ll
#define ll long long
using namespace std;
ll prime[maxn], g[maxn], u[maxn], pr[maxn], p[maxn];
bool mark[maxn];
void init()
{
    ll i, j, t;
    u[1]=1;
    for(i=2;i<maxn;i++)
    {
        if(!mark[i])
        {
            prime[++*prime]=i;
            pr[i]=p[i]=i;
            u[i]=(-i+1+mod)%mod;
        }
        else
        {
            u[i]=u[i/p[i]]*u[p[i]]%mod;
            if(i==pr[i]*pr[i])u[i]=(-pr[i]+mod)%mod;
        }
        for(j=1;j<=*prime and i*prime[j]<maxn;j++)
        {
            t=i*prime[j];
            mark[t]=1;
            pr[t]=prime[j];
            if(i%prime[j]==0)p[t]=p[i]*prime[j];
            else p[t]=prime[j];
            if(i%prime[j]==0)break;
        }
    }
    for(i=1;i<maxn;i++)g[i]=i*(i+1)/2%mod;
    for(i=1;i<maxn;i++)u[i]=u[i]*i%mod;
    for(i=1;i<maxn;i++)u[i]=(u[i]+u[i-1])%mod;
}
void calc(ll n, ll m)
{
    ll t, last;
    ll ans=0;
    if(n<m)swap(n,m);
    for(t=1;t<=m;t=last+1)
    {
        last=min(n/(n/t),m/(m/t));
        ans=(ans+(g[n/t]*g[m/t])%mod*(u[last]-u[t-1]+mod)%mod)%mod;
    }
    printf("%lld\n",ans);
}
int main()
{
    ll T, n, m;
    init();
    scanf("%lld",&T);
    while(T--){scanf("%lld%lld",&n,&m);calc(n,m);}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值