bzoj3994: [SDOI2015]约数个数和(莫比乌斯反演+分块)
www.cnblogs.com/shaokele/
bzoj3994: [SDOI2015]约数个数和##
Time Limit: 20 Sec
Memory Limit: 128 MBDescription###
设d(x)为x的约数个数,给定N、M,求 $$\sum_{i=1}{n}\sum_{j=1}d(i j)$$
Input###
输入文件包含多组测试数据。
第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。
Output###
T行,每行一个整数,表示你所求的答案。
Sample Input###
2
7 4
5 6
Sample Output###
110
121
题目地址: bzoj3994: [SDOI2015]约数个数和
题目大意: 题目很简洁了:)####
题解:
\代码渲染好像出了点问题......
AC代码
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int N=500005;
int n,m,Q,tot;
int u[N],f[N],g[N],pri[N];
bool fl[N];
inline void init(){
u[1]=f[1]=1;
for(int i=2;i<=N;i++){
if(!fl[i]){
pri[++tot]=i;
g[i]=1;
u[i]=-1;
f[i]=2;
}
for(int j=1;j<=tot && i*pri[j]<=N;j++){
fl[i*pri[j]]=1;
if(i%pri[j]==0){
g[i*pri[j]]=g[i]+1;
u[i*pri[j]]=0;
f[i*pri[j]]=f[i]/(g[i]+1)*(g[i]+2);
}else{
g[i*pri[j]]=1;
u[i*pri[j]]=-u[i];
f[i*pri[j]]=f[i]*2;
}
}
}
for(int i=2;i<=N;i++)
f[i]+=f[i-1],u[i]+=u[i-1];
}
int main(){
init();
scanf("%d",&Q);
while(Q--){
scanf("%d%d",&n,&m);
if(n>m)swap(n,m);
ll ans=0;
int l,r;
for(l=1;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(ll)(u[r]-u[l-1])*f[n/l]*f[m/l];
}
printf("%lld\n",ans);
}
return 0;
}