BZOJ 3529 [Sdoi2014]数表 ——莫比乌斯反演 树状数组

$ans=\sum_{i=1}^n\sum_{j=1}^n\sigma(gcd(i,j))$

枚举gcd为d的所有数得到

$ans=\sum_{d<=n}\sigma(d)*g(d)$

$g(d)$表示所有(i,j)=d的二元组的数量。

那么可以反演得到$g(i)=\sum_{i \mid d}\mu(\lfloor d/i \rfloor )*\lfloor n/d \rfloor * \lfloor m/d \rfloor$

然后代入然后xjb变换可得

$ans=\sum_{d<=n}\lfloor n/d \rfloor * \lfloor m/d \rfloor \sum_{i \mid d}\mu( \lfloor d/i \rfloor ) * \sigma(i) $

然后我们要求出$\sum_{i \mid d}\mu(\lfloor d/i \rfloor ) *\sigma(i) $的前缀和就可以$\sqrt n$的时间内解决了

那么我们可以用每个数去暴力更新倍数即可,但是它是一个积性函数,是可以在$\Theta(n)$的时间内筛出来的。

但是有A的条件,我们可以去维护前缀和用树状数组,暴力更新倍数即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define md 2147483647
#define inf 0x3f3f3f3f
#define maxn 100005
struct query{int n,m,k,id,ans;}a[maxn];
 
struct Bit_Tree{
    int x[maxn];
    void add(int i,int f)
    {for (;i<maxn;i+=i&(-i))x[i]+=f;}
    int gs(int i)
    {
        int ret=0;
        for (;i;i-=i&(-i)) ret+=x[i];
        return ret;
    }
}BT;
 
int sigma[maxn],pr[maxn],top,mu[maxn],min_fac_a[maxn],min_fac_sum[maxn],rk[maxn];
 
void init()
{
    sigma[1]=1;mu[1]=1;rk[1]=1;
    F(i,2,maxn-1)
    {
        rk[i]=i;
        if (!sigma[i])
        {
            pr[++top]=i;
            min_fac_a[i]=i;
            sigma[i]=min_fac_sum[i]=i+1;
            mu[i]=-1;
        }
        F(j,1,top)
        {
            if (pr[j]*i>=maxn) break;
            if (i%pr[j]==0)
            {
                sigma[pr[j]*i]=sigma[i]/min_fac_sum[i]*
                    (min_fac_sum[pr[j]*i]=min_fac_sum[i]+min_fac_a[i]*pr[j]);
                min_fac_a[pr[j]*i]=min_fac_a[i]*pr[j];
                mu[pr[j]*i]=0;
                break;
            }
            sigma[pr[j]*i]=sigma[pr[j]]*sigma[i];
            min_fac_a[pr[j]*i]=pr[j];
            min_fac_sum[pr[j]*i]=pr[j]+1;
            mu[pr[j]*i]=-mu[i];
        }
    }
}
 
int t;
 
bool cmp(query x,query y)
{return x.k<y.k;}
 
bool cmp2(query x,query y)
{return x.id<y.id;}
 
bool cmp3(int x,int y)
{return sigma[x]<sigma[y];}
 
void add(int i)
{
    F(j,1,inf)
    {
        if (i*j>=maxn) break;
        BT.add(i*j,sigma[i]*mu[j]);
    }
}
 
int solve(int n,int m)
{
    int ret=0;
    for (int i=1,last=0;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ret+=(BT.gs(last)-BT.gs(i-1))*(n/i)*(m/i);
    }
    return ret&md;
}
 
int main()
{
    init();
    sort(rk+1,rk+maxn,cmp3);
    scanf("%d",&t);
    F(i,1,t)
    {
        scanf("%d%d%d",&a[i].n,&a[i].m,&a[i].k);
        if (a[i].n>a[i].m) swap(a[i].n,a[i].m);
        a[i].id=i;
    }
    sort(a+1,a+t+1,cmp);
    int now=0;
    F(i,1,t)
    {
        while (sigma[rk[now+1]]<=a[i].k) add(rk[++now]);
        a[i].ans=solve(a[i].n,a[i].m);
    }
    sort(a+1,a+t+1,cmp2);
    F(i,1,t) printf("%d\n",a[i].ans);
}

  

posted @ 2017-03-21 20:14  SfailSth  阅读(201)  评论(2编辑  收藏  举报