# BZOJ3994: [SDOI2015]约数个数和

## Description

设d(x)为x的约数个数，给定N、M，求

## Output

T行，每行一个整数，表示你所求的答案。

2
7 4
5 6

110
121

## HINT

1<=N, M<=50000

1<=T<=50000

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
if(head==tail) {
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
}
return *head++;
}
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
typedef long long ll;
const int maxn=50010;
int mu[maxn],f[maxn],vis[maxn],pri[maxn],cnt;
ll d[maxn];
void gen(int n) {
mu[1]=1;d[1]=1;
rep(i,2,n) {
if(!vis[i]) pri[++cnt]=i,mu[i]=-1,d[i]=2,f[i]=1;
rep(j,1,cnt) {
if(i*pri[j]>n) break;
vis[i*pri[j]]=1;
if(i%pri[j]==0) {
mu[i*pri[j]]=0;
f[i*pri[j]]=f[i]+1;
d[i*pri[j]]=d[i]/(f[i]+1)*(f[i]+2);
break;
}
mu[i*pri[j]]=-mu[i];
d[i*pri[j]]=d[i]*d[pri[j]];
f[i*pri[j]]=1;
}
}
rep(i,2,n) d[i]+=d[i-1],mu[i]+=mu[i-1];
}
ll solve(int n,int m) {
if(n>m) swap(n,m);ll ans=0;
rep(i,1,n) {
int last=min(n/(n/i),m/(m/i));
ans+=(mu[last]-mu[i-1])*d[n/i]*d[m/i];
i=last;
}
return ans;
}
int main() {
gen(50000);
dwn(T,read(),1) printf("%lld\n",solve(read(),read()));
return 0;
}
View Code

posted @ 2016-03-04 16:09  wzj_is_a_juruo  阅读(182)  评论(0编辑  收藏  举报