zoukankan      html  css  js  c++  java
  • 【BZOJ3529】数表(SDOI2014)-莫比乌斯反演+树状数组

    测试地址:数表
    做法:本题需要用到莫比乌斯反演+树状数组。
    首先忽略a的限制,我们要求的是:
    ans=i=1nj=1mD(gcd(i,j))
    其中D(i)i的约数和。
    我们把上式改成枚举公因数d,不妨设nm,则:
    ans=d=1nD(d)i=1nj=1m[gcd(i,j)=d]
    f(d)=i=1nj=1m[gcd(i,j)=d],我们发现这就是求gcd等于d的数对个数(这简直是句废话)。
    又令F(d)=d|if(i),显然F(d)gcd等于d倍数的数对个数,那么也有F(d)=ndmd。根据莫比乌斯反演定理的第二种形式,有:
    f(d)=d|iμ(id)F(i)=d|iμ(id)nimi
    把这个式子带进ans那个式子,有:
    ans=d=1nD(d)d|iμ(id)nimi
    交换d,i的位置,有:
    ans=i=1nnimid|iD(d)μ(id)
    显然我们如果预处理出g(i)=d|iD(d)μ(id)的前缀和,就可以用数论分块处理每个询问了。
    那么现在我们考虑a的限制,实际上a是在限制只有D(i)aD(i)g(i)有贡献,因此我们把所有询问按a从小到大排序,对新产生的贡献暴力在g中单点修改,因为D(i)g(j)产生贡献当且仅当i|j,那么修改次数显然是nlogn级别的,然后要在数论分块中维护g的前缀和查询,这个显然可以用常数小又好写的树状数组解决。
    那么我们就解决了此题,时间复杂度为O(Qnlogn+nlog2n)。注意到这题模数很特殊,直接用int自然溢出,最后输出时对2311取个按位与就行了。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int T,p[100010];
    int maxn,D[100010],mu[100010],s[100010],ans[20010];
    int prime[100010];
    bool vis[100010]={0};
    struct query
    {
        int id,n,m,a;
    }q[20010];
    
    bool cmp(query a,query b)
    {
        return a.a<b.a;
    }
    
    bool cmpp(int a,int b)
    {
        return D[a]<D[b];
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int x,int c)
    {
        for(int i=x;i<=maxn;i+=lowbit(i))
            s[i]+=c;
    }
    
    int sum(int x)
    {
        int ans=0;
        for(int i=x;i;i-=lowbit(i))
            ans+=s[i];
        return ans;
    }
    
    void init()
    {
        scanf("%d",&T);
        maxn=0;
        for(int i=1;i<=T;i++)
        {
            scanf("%lld%lld%lld",&q[i].n,&q[i].m,&q[i].a);
            if (q[i].n>q[i].m) swap(q[i].n,q[i].m);
            maxn=max(maxn,q[i].n);
            q[i].id=i;
        }
        sort(q+1,q+T+1,cmp);
    
        for(int i=1;i<=maxn;i++)
            for(int j=1;i*j<=maxn;j++)
                D[i*j]=D[i*j]+i;
        for(int i=1;i<=maxn;i++)
            p[i]=i;
        sort(p+1,p+maxn+1,cmpp);
    }
    
    void calc_mu()
    {
        mu[1]=1;
        prime[0]=0;
        for(int i=2;i<=maxn;i++)
        {
            if (!vis[i])
            {
                prime[++prime[0]]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=prime[0]&&i*prime[j]<=maxn;j++)
            {
                vis[i*prime[j]]=1;
                if (i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;
                    break;
                }
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
    
    int main()
    {
        init();
        calc_mu();
    
        int nowp=1;
        for(int i=1;i<=T;i++)
        {
            while(D[p[nowp]]<=q[i].a)
            {
                for(int j=1;j*p[nowp]<=maxn;j++)
                    add(j*p[nowp],D[p[nowp]]*mu[j]);
                nowp++;
            }
            int n=q[i].n,m=q[i].m;
            ans[q[i].id]=0;
            for(int j=n;j>=1;j=max(n/(n/j+1),m/(m/j+1)))
            {
                int l=max(n/(n/j+1)+1,m/(m/j+1)+1),r=j;
                ans[q[i].id]=ans[q[i].id]+(sum(r)-sum(l-1))*(n/j)*(m/j);
            }
        }
    
        for(int i=1;i<=T;i++)
            printf("%d
    ",ans[i]&2147483647);
    
        return 0;
    }
  • 相关阅读:
    八. 输入输出(IO)操作2.面向字符的输入流
    八. 输入输出(IO)操作1.输入输出基本概念
    七. 多线程编程11.线程的挂起、恢复和终止
    七. 多线程编程10.线程死锁
    nginx 配置身份验证 http_auth_basic_module
    liunx mysql 备份
    8080 端口只允许内网访问配置
    nginx 配置白名单
    liunx tomcat 运行模式apr
    liunx contos 7.4 安装redis集群
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793405.html
Copyright © 2011-2022 走看看