bzoj 4407

莫比乌斯反演

还是推式子:

设$f(n)=n^{k}$

那就是上一道题了

推的过程如下:

$\sum_{i=1}^{a}\sum_{j=1}^{b}f(gcd(i,j))$

$\sum_{i=1}^{a}\sum_{j=1}^{b}\sum_{d=1}^{min(a,b)}[gcd(i,j)\equiv d]f(d)$

$\sum_{d=1}^{min(a,b)}f(d)\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(i,j)\equiv d]$

$\sum_{d=1}^{min(a,b)}f(d)\sum_{i=1}^{\frac{a}{d}}\sum_{j=1}^{\frac{b}{d}}[gcd(i,j)\equiv 1]$

$\sum_{d=1}^{min(a,b)}f(d)\sum_{i=1}^{\frac{a}{d}}\sum_{j=1}^{\frac{b}{d}}\sum_{t=1}^{min(\frac{a}{d},\frac{b}{d})}\mu(t)$

$\sum_{d=1}^{min(a,b)}f(d)\sum_{t=1}^{min(a,b)}\mu(t)\frac{a}{dt}\frac{b}{dt}$

令$T=dt$,得到:

$\sum_{T=1}^{min(a,b)}\frac{a}{T}\frac{b}{T}\sum_{d|T}f(d)\mu(\frac{T}{d})$

也就是:

$\sum_{T=1}^{min(a,b)}\frac{a}{T}\frac{b}{T}\sum_{d|T}d^{k}\mu(\frac{T}{d})$

考虑线性筛后面那堆东西,仍然分类讨论:

①.筛到的$p$与$i$互质:

此时我们考虑增加一个$p$的贡献,如果增加到$\mu$里,则原先那些直接取反

如果增加到$d^{k}$里,则相当于原先那些乘$p^{k}$

因此$g(ip)=(p^{k}-1)g(i)$

②.筛到的$p$与$i$不互质:

此时我们考虑增加一个$p$的贡献,如果增加到$\mu$里,则原先那些仍然取反

如果增加到$f$里,则原先那些多一个$p^{k}$的贡献

可...等等!

还有一种可能!

再考虑如果原先$\mu$里有一个$p$,然后增加到$f$里,此时会抵消掉取反的效果!

因此只需乘一个$p^{k}$即可

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
const ll mode=1000000007;
int mu[5000005];
int pri[5000005];
ll f[5000005];
ll pow_mul(ll x,ll y)
{
    ll ret=1;
    while(y)
    {
        if(y&1)ret=ret*x%mode;
        x=x*x%mode,y>>=1;
    }
    return ret;
}
bool used[10000005];
int cnt=0;
ll T,x,y,k;
void init()
{
    mu[1]=1;
    f[1]=1;
    for(int i=2;i<=5000000;i++)
    {
        if(!used[i])mu[i]=-1,pri[++cnt]=i,f[i]=(pow_mul(i,k)+mode-1)%mode;
        for(int j=1;j<=cnt&&i*pri[j]<=5000000;j++)
        {
            used[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                mu[i*pri[j]]=0;
                f[i*pri[j]]=f[i]*(f[pri[j]]+1)%mode;
                break;
            }
            mu[i*pri[j]]=-mu[i],f[i*pri[j]]=f[i]*f[pri[j]]%mode;
        }
    }
    for(int i=2;i<=5000000;i++)f[i]+=f[i-1],f[i]%=mode;
}
ll solve(ll a,ll b)
{
    ll las=1,ans=0;
    for(int i=1;i<=a&&i<=b;i=las+1)
    {
        las=min(a/(a/i),b/(b/i));
        ans+=(f[las]-f[i-1]+mode)*(a/i)%mode*(b/i)%mode;
        ans%=mode;
    }
    return ans;
}
template <typename T>inline void read(T &x)
{
    T f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x=c*f;
}
int main()
{
    read(T),read(k);
    init();
    while(T--)
    {
        read(x),read(y);
        printf("%lld\n",solve(x,y));
    }
    return 0;
}

 

posted @ 2019-07-08 11:04  lleozhang  Views(110)  Comments(0Edit  收藏
levels of contents