• BZOJ3529: [Sdoi2014]数表


    3529: [Sdoi2014]数表

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 2029  Solved: 1019
    [Submit][Status][Discuss]

    Description

        有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为
    能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。

    Input

        输入包含多组数据。
        输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。

    Output

        对每组数据,输出一行一个整数,表示答案模2^31的值。

    Sample Input

    2
    4 4 3
    10 10 5

    Sample Output

    20
    148

    HINT

    1 < =N.m < =10^5  , 1 < =Q < =2×10^4

    思路{

      先不考虑多组数据和a的限制.

      最后的答案=∑F(i)*G(i). F(i)为i的约数和,G(d)为GCD(i,j)==d,i∈[1,n],j∈[1,m]的方案数,

      F可以log的筛出来,套路莫比乌斯反演可得G(i)=∑(i|d)μ(d/i)*(m/d)*(n/d)

      Ans={(min(n,m))∑(d=1)}(m/d)*(n/d)*∑(i|d)μ(d/i)*F(i)

      那么前半段分块,后半段可以用一个前缀和搞就可以了.

      由于有询问的大小和a的限制,我们不妨考虑能够动态维护区间和的东西---树状数组.

      把F按照大小排序,询问的a按照大小也排好.那么读入一个询问把F按照下标依次插入,log求取前缀和就可以解决本题.

    }

    #include<bits/stdc++.h>
    #define RG register
    #define il inline
    #define db double
    #define LL long long
    #define N 100100
    #define mod 2147483648
    using namespace std;
    LL mu[N],p[N];bool vis[N];
    struct Dat{
      LL num;
      int pos;
    }F[N];
    bool comp(const Dat & a,const Dat & b){return a.num<b.num;}
    void pre(){
      mu[1]=1;
      for(int i=2;i<N;++i){
        if(!vis[i])mu[i]=-1,p[++p[0]]=i;
        for(int j=1;j<=p[0]&&p[j]*i<N;++j){
          vis[i*p[j]]=true;
          if(i%p[j])mu[i*p[j]]=-mu[i];
          else {mu[i*p[j]]=0;break;}
        }
      }
      for(int i=1;i<N;++i)
        for(int j=i;j<N;j+=i)
          F[j].num+=i;
      for(int i=1;i<N;++i)F[i].pos=i;
    }
    int T,n,m;
    struct ask{
      int n,m,a,id;LL ans;
      void read(int x){id=x,scanf("%d%d%d",&n,&m,&a);}
    }Q[N];
    bool Comp(const ask & a,const ask & b){return a.a<b.a;}
    bool cmp(const ask & a,const ask & b){return a.id<b.id;}
    LL tree[N];
    #define lowbit ( (i) & (-i) )
    void Insert(int pos,LL num){for(int i=pos;i<N;i+=lowbit)tree[i]+=num;return;}
    LL Query(int pos){LL sum=0;for(int i=pos;i;i-=lowbit)sum+=tree[i];return sum;}
    int main(){
      pre();scanf("%d",&T);
      for(int i=1;i<=T;++i)Q[i].read(i);
      sort(Q+1,Q+T+1,Comp);
      sort(F+1,F+N,comp);int last=1;
      for(int h=1;h<=T;++h){LL ans(0);
        while(F[last].num<=Q[h].a&&last<N){
          for(int j=F[last].pos;j<N;j+=F[last].pos)
        Insert(j,F[last].num*mu[j/F[last].pos]);
          last++;
        }n=Q[h].n,m=Q[h].m;LL lim=min(n,m);
        for(LL l=1,r;l<=lim;l=r+1){
          r=min(n/(n/l),m/(m/l));
          LL bas=(n/l)*(m/l);
          ans+=(bas*((Query(r)-Query(l-1))));
        }
        if(ans<0){
          ans-=(1+ans/mod)*mod;
        }
        else ans%=mod;
        Q[h].ans=ans;
      }
      sort(Q+1,Q+T+1,cmp);
      for(int i=1;i<=T;++i)cout<<Q[i].ans<<"
    ";
      return 0;
    }
    
  • 相关阅读:
    快速开始
    阿里为什么选择RocketMQ
    4 分布式消息队列的协调者
    9 首个Apache中间件顶级项目
    3、用适合的方式发送和接收消息
    2 生产环境下的配置和使用
    TOMCAT加载两次war包(重复加载)
    Google Protocol Buffer 的使用(二)
    Google Protocol Buffer 的使用(一)
    PostgreSQL及PostGIS使用
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7476564.html
Copyright © 2020-2023  润新知