bzoj3994【SDOI2005】约数个数和

3994: [SDOI2015]约数个数和

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 527   Solved: 344
[ Submit][ Status][ Discuss]

Description

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

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。

Output

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

Sample Input

2
7 4
5 6

Sample Output

110
121

HINT

 1<=N, M<=50000


1<=T<=50000

Source

Round 1 感谢yts1999上传




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 50000
using namespace std;
int t,n,m,tot;
int mu[maxn+5],pri[maxn+5],cnt[maxn+5],d[maxn+5];
bool mark[maxn+5];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void pre()
{
	mu[1]=1;d[1]=1;
	F(i,2,maxn)
	{
		if (!mark[i]){pri[++tot]=i;mu[i]=-1;d[i]=2;cnt[i]=1;}
		for(int j=1;j<=maxn&&pri[j]*i<=maxn;j++)
		{
			mark[pri[j]*i]=true;
			if (i%pri[j]==0)
			{
				mu[i*pri[j]]=0;
				d[i*pri[j]]=d[i]/(cnt[i]+1)*(cnt[i]+2);
				cnt[i*pri[j]]=cnt[i]+1;
				break;
			}
			mu[i*pri[j]]=-mu[i];
			d[i*pri[j]]=d[i]*2;
			cnt[i*pri[j]]=1;
		}
	}
	F(i,1,maxn) mu[i]+=mu[i-1],d[i]+=d[i-1];
}
int main()
{
	pre();
	t=read();
	while (t--)
	{
		n=read();m=read();
		if (n>m) swap(n,m);
		ll ans=0;
		for(int i=1,pos;i<=n;i=pos+1)
		{
			pos=min(n/(n/i),m/(m/i));
			ans+=(ll)(mu[pos]-mu[i-1])*d[n/i]*d[m/i];
		}
		printf("%lld\n",ans);
	}
}


你可能感兴趣的:(bzoj,莫比乌斯反演)