BZOJ 3994: [SDOI2015]约数个数和

3994: [SDOI2015]约数个数和

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 898  Solved: 619
[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上传

分析:

首先$d(x)$是一个积性函数,其次这个东西有一个很神奇的性质:

$d(nm)=\sum _{x\mid n} \sum _{y\mid m} [gcd(x,y)==1]$

证明如下:(懒得写了...公式打起来好麻烦...直接摘抄Sengxian的解释...QwQ)

于是接下来就直接莫比乌斯反演就好了...

$\sum _{x=1}^{n} \sum _{y=1}^{m} \left \lfloor \frac{n}{x} \right \rfloor \left \lfloor \frac{m}{y} \right \rfloor \sum _{d\mid x  d\mid y}\mu (d)$

$=\sum _{d=1}^{x} \mu(d) \sum _{i=1}^{\frac {n}{d}} \left \lfloor \frac{n}{id} \right \rfloor \sum _{j=1}^{\frac {m}{d}} \left \lfloor \frac{m}{jd} \right \rfloor$

现在有一个有用的公式:

$\left \lfloor \frac{n}{xy} \right \rfloor=\left \lfloor \frac{ \left \lfloor \frac{n}{x} \right \rfloor }{y} \right \rfloor$

于是乎,我们定义$f(x)=\sum _{i=1}^{x} \left \lfloor \frac{x}{i} \right \rfloor$,

那么式子就变成酱紫:

$\sum _{d=1}^{n} \mu(d) f(\left \lfloor \frac{n}{d} \right \rfloor) f(\left \lfloor \frac{m}{d} \right \rfloor)$

时间复杂度:$O(N\sqrt{N}+T\sqrt{N})$

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=50000+5;

int n,m,cas,cnt,mu[maxn],pri[maxn],vis[maxn];
long long ans,f[maxn];

inline long long calc(int x){
	long long res=0;
	for(int i=1,r;i<=x;i=r+1){
		r=x/(x/i);
		res+=(x/i)*(r-i+1);
	}
	return res;
}

inline void prework(void){
	mu[1]=1;
	for(int i=2;i<=50000;i++){
		if(!vis[i])
			vis[i]=1,pri[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*pri[j]<=50000;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0){
				mu[i*pri[j]]=0;break;
			}
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<=50000;i++) mu[i]+=mu[i-1],f[i]=calc(i);
}

signed main(void){
	scanf("%d",&cas);prework();
	while(cas--){
		scanf("%d%d",&n,&m);
		if(n>m) swap(n,m);ans=0;
		for(int i=1,r;i<=n;i=r+1){
			r=min(n/(n/i),m/(m/i));
			ans+=f[n/i]*f[m/i]*(mu[r]-mu[i-1]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  



By NeighThorn

时间: 2024-10-14 00:50:54

BZOJ 3994: [SDOI2015]约数个数和的相关文章

BZOJ 3994 [SDOI2015]约数个数和 (神定理+莫比乌斯反演)

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit:128 MB Submit: 239  Solved: 176 [Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7

【刷题】BZOJ 3994 [SDOI2015]约数个数和

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 Solution 莫比乌斯反演 但这题更多的是套路 首先,一个神奇的东东:\(d(nm)= \

BZOJ 3994 Sdoi2015 约数个数和 莫比乌斯反演

题目大意:求∑ni=1∑mj=1d(ij) 首先我们有一个很神的结论: ∑ni=1∑mj=1d(ij)=∑ni=1∑mj=1?ni??mj?[gcd(i,j)==1] 这个结论是怎么来的呢?我们可以先证明这个: d(nm)=∑i|n∑j|m1?1[gcd(i,j)==1] 显然这个式子的前缀和就是上面的式子 现在我们来证明这个式子是对的 我们分开讨论每一个质数p对答案的贡献 不妨设n=n′?pk1,m=m′?pk2 那么左式中p的贡献显然是k1+k2+1 右式中只考虑p的话,满足要求的数对(i,

【BZOJ 3994】3994: [SDOI2015]约数个数和(莫比乌斯反演)

3994: [SDOI2015]约数个数和 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 感谢yts199

3994: [SDOI2015]约数个数和

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 858  Solved: 587[Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7

[BZOI 3994] [SDOI2015]约数个数和

[BZOI 3994] [SDOI2015]约数个数和 题面 设d(x)为x的约数个数,给定N.M,求\(\sum _{i=1}^n \sum_{i=1}^m d(i \times j)\) T组询问,\(N,M,T \leq 50000\) 分析 首先有一个结论 \[d(nm)= \sum _{i |n} \sum _{j|m} [gcd(i,j)=1]\] 这是因为nm的约数都可以表示为\(i \times \frac{m}{j}\)的形式,并且为了不重复算,要保证\(gcd(i,j)=1\

[SDOI2015] 约数个数和 (莫比乌斯反演)

[SDOI2015]约数个数和 题目描述 设d(x)为x的约数个数,给定N.M,求 \(\sum^N_{i=1}\sum^M_{j=1}d(ij)\) 输入输出格式 输入格式: 输入文件包含多组测试数据.第一行,一个整数T,表示测试数据的组数.接下来的T行,每行两个整数N.M. 输出格式: T行,每行一个整数,表示你所求的答案. 输入输出样例 输入样例#1: 2 7 4 5 6 输出样例#1: 110 121 说明 \(1<=N, M<=50000\) \(1<=T<=50000\

【bzoj3994】[SDOI2015]约数个数和 莫比乌斯反演

题目描述 设d(x)为x的约数个数,给定N.M,求   输入 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. 输出 T行,每行一个整数,表示你所求的答案. 样例输入 2 7 4 5 6 样例输出 110 121 题解 莫比乌斯反演 根据 bzoj4176 推出的结论, 那么就有: 预处理mu及其前缀和. 由于要处理多组询问,所以需要用O(n√n)的时间预处理出f,然后对于每组询问分块来求. #include <cstdio> #incl

Sdoi2015约数个数和题解莫比乌斯反演

题目描述 T组数据,求ΣNi=1ΣMj=1d(ij),d(x)代表x的约数个数. 1≤N,M,T≤105 题解 首先,膜拜一下PoPoQQQ大神及其题解 然后,有一个神奇的结论:ΣNi=1ΣMj=1d(ij)=ΣNi=1ΣMj=1[Ni][Mj][gcd(i,j)=1] 要证上式,只需证d(nm)=Σi|nΣj|m[gcd(i,j)=1],因为上式即为该式的前缀和形式. 分开考虑每个质数p对答案的贡献.设n=n′pk1,m=m′pk2,那p对d(nm)的贡献就是k1+k2+1,对等式右边的贡献是