BZOJ 2693: jzptab 莫比乌斯反演 + 积性函数 + 筛法

Description

Input

题解: 

这次是多组询问,上次推出来的式子是 $O(n)$ 的,我们需要更快的算法.
 
先定义几个后面可能会用到的函数:(在本题弱化版中推出来的)
 
$Sum(n,m)=\frac{n(n+1)}{2}\times \frac{m(m+1)}{2}$
 
$calc(n,m)=\sum_{d=1}^{n}\mu(d)d^2Sum(\frac{n}{d},\frac{m}{d})$
 
则 $ans=\sum_{d=1}^{n}d\times calc(\frac{n}{d},\frac{m}{d})$
 
把式子展开:
 
$=\sum_{d=1}^{n}d\sum_{b=1}^{\frac{n}{d}}\mu(b)b^2Sum(\frac{n}{db},\frac{m}{db})$
 
令 $D=db$ ,得:
 
$\sum_{D=1}^{n}Sum(\frac{n}{D},\frac{m}{D})\sum_{d|D}d\times\mu(\frac{D}{d})\times(\frac{D}{d})^2$ 
 
看上去有点别扭,再稍微改动一下:
 
$\sum_{D=1}^{n}Sum(\frac{n}{D},\frac{m}{D})\sum_{d|D}\frac{D}{d}\times\mu(d)\times d^2$ 
 
前面 $\sum_{D=1}^{n}Sum(\frac{n}{D},\frac{m}{D})$ 这个部分好像没法优化了,只能$\sqrt{n}$ 硬算.
 
好在 $f(D)=\sum_{d|D}\frac{D}{d}\times\mu(d)\times d^2$ 是一个积性函数,可以线筛.
 
只需分三种情况讨论即可:
 
(1) $x$ 为质数.$\Rightarrow$ $f(x)=x^{2}-x$ (只有 $d=1,d=D$ 时有贡献)
 
(2) $a,b$ 互质.$\Rightarrow$ $f(ab)=f(a)f(b)$ (积性函数定义)
 
(3) $p|i$ ,且 $p$ 为质数, $i$ 中 $p$ 的指数为 $1$
 
$f(i)=\sum_{d|i}\frac{i}{d}\times\mu(d)\times d^2$
 
$f(i\times p)=\sum_{d|i\times p}\frac{i\times p}{d}\times\mu(d)\times d^2$
 
由 $\mu$ 的定义可知,当一个数有质因子次幂大于 $1$ 时值为 $0$ ,即无贡献.
 
那么,$f(i\times p)$ ,$d$ 中 $p$ 的幂次必小于等于 $1$.
 
而 $f(i)$ 中所有 $d$ 中 $p$ 的次幂本来就小于等于 $1$.
 
故 $f(i)$ 与 $f(i\times p)$ 中有贡献的因子是完全相同的.
 
唯一不同就是 $f(i\times p)=f(i)\times p$
 
既然讨论好上面 $3$ 种情况,我们就可以愉快地线筛 $f(x)$ 啦!!
#include<bits/stdc++.h>
#define ll long long 
#define M 10001000
#define maxn 10200100 
#define MOD 100000009
using namespace std;
int cnt, tot;   
int vis[maxn],mu[maxn], prime[maxn]; 
ll h[maxn], sumv[maxn];  
void init()
{
    int i,j; 
    h[1]=1; 
    for(i=2;i<M;++i) 
    {
        if(!vis[i]) prime[++tot]=i, h[i]=(i-(ll)i*i)%MOD; 
        for(j=1;j<=tot&&prime[j]*i<M;++j) 
        {
            vis[prime[j]*i]=1; 
            if(i%prime[j]==0) 
            {
                h[prime[j]*i]=(prime[j]*h[i])%MOD; 
                break; 
            }
            else  h[prime[j]*i]=(h[prime[j]]*h[i])%MOD; 
        }
    }
    for(i=1;i<M;++i)   sumv[i]=(sumv[i-1]+h[i])%MOD; 
}
ll SUM(ll x,ll y)
{
    x%=MOD, y%=MOD; 
    ll r1=(x*(x+1)>>1)%MOD; 
    ll r2=(y*(y+1)>>1)%MOD;
    return (r1*r2)%MOD;  
}
ll query(ll n,ll m)
{
    int i,last,re=0,j; 
    if(n>m) swap(n,m); 
    for(i=1;i<=n;i=j+1)
    {
        j=min(n/(n/i), m/(m/i)); 
        re += SUM(n/i, m/i) * (sumv[j]-sumv[i-1])%MOD; 
        re%=MOD; 
    }
    return (re+MOD)%MOD; 
}
int main()
{
    init(); 
    int n,m,T; 
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m); 
        printf("%lld\n",query(n,m)); 
    }
    return 0; 
}

  



posted @ 2019-06-25 21:12  EM-LGH  阅读(208)  评论(0编辑  收藏  举报