• [SDOI2014]数表


    [SDOI2014]数表

    在一张(n imes m)数表中,第i行第j列的数字为即能整除i又能整除j的自然数之和,Q组询问,询问这张数表中不大于a的数之和,1 < =n.m < =10^5 , 1 < =Q < =2*10^4。

    转换为约数计数问题,不难有

    [ans=sum_{i=1}^nsum_{j=1}^msigma(gcd(i,j)) ]

    因为限制数表中的数不大于a,于是我们得设的式子中要有(sigma(gcd(i,j))),后面推式也要保留其,于是设(nleq m),有

    [ans=sum_{d=1}^nsigma(d)sum_{i=1}^nsum_{j=1}^m(gcd(i,j)==d) ]

    [f(d)=sum_{i=1}^nsum_{j=1}^m(gcd(i,j)==d) ]

    [F(d)=[n/d][m/d] ]

    由Mobius反演定理有

    [f(d)=sum_{d|x}[n/x][m/x]mu(x/d) ]

    代入有

    [ans=sum_{d=1}^nsigma(d)sum_{d|x}[n/x][m/x]mu(x/d)= ]

    [sum_{x=1}^n[n/x][m/x]sum_{d|x}sigma(d)mu(x/d) ]

    注意到(sigma)为积性函数,我们可以线性递推,而后式显然可以维护,前式又可以整除分块,于是如果没有a的限制,我们已经可以做了,
    而此时能贡献的只有(sigma(d)leq a),维护的东西要求小于某个数,而询问又可以离线,于是考虑给a排序,给(sigma)排序,按照a的增加,慢慢地加入我们需要维护的后式的前缀和,所以我们需要支持快速修改,而树状数组就是一个不错的选择,所以不难得知时间复杂度应为(O(nlog(n)+Qsqrt{n}))

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    #define sxr 100000
    #define yyb 2147483647
    #define swap(x,y) x^=y^=x^=y
    using namespace std;
    struct query{
        int n,m,a,id;
        il bool operator<(const query&x){
            return a<x.a;
        }
        il void sort(){
            if(n>m)swap(n,m);
        }
    }q[20001];
    template<class f1,class f2,f2 key>
    struct lowbit{
        f1 s[key+1];
        il void add(int p,int x){
            while(p<=key)
                s[p]+=x,p+=(-p)&p;
        }
        il f1 sum(int p){
            f1 ans(0);
            while(p)ans+=s[p],p-=(-p)&p;
            return ans;
        }
    };
    struct ysh{
        int id,dat;
        il bool operator<(ysh&x){
            return dat<x.dat;
        }
    }ds[sxr+1];
    bool check[sxr+1];
    int prime[sxr+1],pt,mb[sxr+1],
        df[sxr+1],ans[20001];
    lowbit<int,int,sxr+1>czf;
    il ll ask(int);
    il int min(int,int);
    il void prepare(int),read(int&);
    int main(){
        int lsy,i,j,k,l;prepare(sxr),read(lsy);
        for(i=1;i<=lsy;++i)
            read(q[i].n),read(q[i].m),read(q[i].a),
                q[i].id=i,q[i].sort();
        sort(q+1,q+lsy+1);
        for(i=1,j=1;i<=lsy;++i){
            while(ds[j].dat<=q[i].a&&j<=sxr){
                for(k=ds[j].id;k<=sxr;k+=ds[j].id)
                    czf.add(k,ds[j].dat*mb[k/ds[j].id]);
                ++j;
            }
            for(k=1;k<=q[i].n;k=l+1)
                l=min(q[i].n/(q[i].n/k),q[i].m/(q[i].m/k)),
                    ans[q[i].id]+=(q[i].n/k)*(q[i].m/k)*(czf.sum(l)-czf.sum(k-1));
        }for(i=1;i<=lsy;++i)printf("%d
    ",ans[i]&yyb);
        return 0;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    il int min(int a,int b){
        return a<b?a:b;
    }
    il void prepare(int n){
        int i,j;mb[1]|=ds[1].id|=ds[1].dat|=df[1]|=true;
        for(i=2;i<=n;++i){
            if(!check[i])mb[i]=-1,ds[i].dat=i+1,
                             df[i]=i+1,prime[++pt]=i;
            for(j=1;j<=pt&&prime[j]<=n/i;++j){
                check[i*prime[j]]|=true;
                if(!(i%prime[j])){
                    df[i*prime[j]]=df[i]*prime[j]+1;
                    ds[i*prime[j]].dat=ds[i].dat/df[i]*df[i*prime[j]];
                    break;
                }mb[i*prime[j]]=~mb[i]+1,
                     ds[i*prime[j]].dat=ds[i].dat*ds[prime[j]].dat,
                     df[i*prime[j]]=df[prime[j]];
            }ds[i].id=i;
        }sort(ds+1,ds+n+1);
    }
    
    
  • 相关阅读:
    shell 操作钉钉机器人实现告警提醒
    谨慎 mongodb 关于数字操作可能导致类型及精度变化
    数据库如何应对保障大促活动
    SQL Server Alwayson架构下 服务器 各虚拟IP漂移监控告警的功能实现 -1(服务器视角)
    通过 Telegraf + InfluxDB + Grafana 快速搭建监控体系的详细步骤
    MySQL数据库Inception工具学习与测试 笔记
    MongoDB 中数据的替换方法实现 --类Replace()函数功能
    MongoDB 中的【加减乘除】运算
    MySQL索引设计需要考虑哪些因素?
    关于SQL Server 数据库归档的一些思考和改进
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10797023.html
Copyright © 2020-2023  润新知