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<<"\n";
  return 0;
}

 

posted @ 2017-09-05 00:04  QYP_2002  阅读(149)  评论(0编辑  收藏  举报