bzoj_3529 数表

首先不考虑a的限制

设 S(i)为i的约数和

据约数和定理

先将i分解因数

$$ i=p_1^{q_1}p_2^{q_2}...p_k^{q_k}$$

$$S(i)=\prod_{i=1}^k\sum_{j=0}^{q_i}p_i^j$$

当i与j互质时,S(i*j)=S(i)*S(j),满足积性函数性质,所以可以线性删出来

设g(i)为i最小质因数各幂次的加和

1.当i是质数,g(i)=S(i)=i+1

2.当i不与p(质数)互质是,S(i*p)=S(i)/g(i)*g(i*p)

3.当i与p互质时,S(i*p)=S(i)*(p+1)

(具体可见code)

题目让求$$ans=\sum_{i=1 j=1}^{i<=n j<=m}S(gcd(i,j))$$

设f(i)为gcd(x,y)==i的(x,y)数

   F(i)为i|gcd(x,y)的(x,y)数

$$ f(i)=\sum_{i|d}\mu(\frac{d}{i})F(d)$$

$$ f(i)=\sum_{i|d}\mu(\frac{d}{i})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{i}\rfloor$$

那么

$$ans=\sum_{i=1}^{min(n,m)}S(i)f(i)$$

$$(枚举约数) ans=\sum_{i=1}^{min(n,m)}S(i)\sum_{i|d}\mu(\frac{d}{i})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor$$

$$(枚举d) ans=\sum_{d=1}^{min(n,m)}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\sum_{i|d}S(i)\mu(\frac{d}{i})$$

然后考虑加上a的限制条件,发现只要离线处理,用树状数组维护后面一项就行了

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=20006;
const int N=100006;

struct VV
{
    int v,order;
    bool friend operator < (VV a,VV b)
    {
        return a.v<b.v;
    }
}ji[N];

int prime[N],cnt;
bool he[N];
int mu[N],g[N];

void chu()
{
    mu[1]=1;g[1]=1;ji[1].v=1;ji[1].order=1;
    for(int i=2;i<N;++i)
    {
        ji[i].order=i;
        if(!he[i])
        {
            prime[++cnt]=i;
            mu[i]=-1;
            g[i]=i+1;
            ji[i].v=i+1;
        }
        for(int j=1;j<=cnt&&prime[j]*i<N;++j)
        {
            he[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                g[i*prime[j]]=g[i]*prime[j]+1;
                ji[i*prime[j]].v=ji[i].v/g[i]*g[i*prime[j]];
                break;
            }
            mu[i*prime[j]]=-mu[i];
            g[i*prime[j]]=prime[j]+1;
            ji[i*prime[j]].v=ji[i].v*(prime[j]+1);
        }
    }

    /*printf("\n");
    for(int i=1;i<=10;++i)
        printf("%d ",ji[i].v);
    printf("\n");*/

    sort(ji+1,ji+N);
}

struct Q
{
    int n,m,A;
    int order;
    bool friend operator < (Q a,Q b)
    {
        return a.A<b.A;
    }
}q[M];

int an[M];
int m;

int c[N];
void add(int pos,int val)
{
    for(int i=pos;i<N;i+=(i&(-i)) )
        c[i]+=val;
}
int qq(int pos)
{
    int ans=0;
    for(int i=pos;i>0;i-=(i&(-i)) )
        ans+=c[i];
    return ans;
}

inline void mk(int pos,int val)
{
    for(int i=pos;i<N;i+=pos )
    {
        
        add(i,val*mu[i/pos]);
    }//cout<<1;
}

int get(int n,int m)
{
    if(n>m)
        swap(n,m);
    int nx;
    int ans=0;
    for(int i=1;i<=n;)
    {
        nx=min( n/(n/i),m/(m/i) );
        ans+=(n/i)*(m/i)*( qq(nx)-qq(i-1) );
        i=nx+1;
    }
    return ans;
}

void work()
{
    int IINF=(1<<31)-1,now=1;
    for(int i=1;i<=m;++i)
    {
        while(ji[now].v<=q[i].A)
            mk(ji[now].order,ji[now].v),++now;
        an[q[i].order]=get(q[i].n,q[i].m)&IINF;
    }
}

int main(){

    //freopen("in.in","r",stdin);

    freopen("sdoi2014shb.in","r",stdin);
    freopen("sdoi2014shb.out","w",stdout);
    //freopen("out.out","w",stdout);

    chu();

    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        q[i].order=i;
        scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].A);
    }
    sort(q+1,q+1+m);
    work();
    for(int i=1;i<=m;++i)
        printf("%d\n",an[i] );
}
bzoj_3529

 

posted @ 2017-10-09 08:31  A_LEAF  阅读(141)  评论(0编辑  收藏  举报