【BZOJ3529】[Sdoi2014]数表 莫比乌斯反演+树状数组

【BZOJ3529】[Sdoi2014]数表

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

题解:首先我们要知道一个数的约数和是nloglogn级别的,所以先不考虑a的限制,我们还是采用熟悉的莫比乌斯反演。

$ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^nf(gcd(i,j))\\=\sum\limits_{d=1}^nf(d)\sum\limits_{i=1}^{\lfloor \frac n d \rfloor}\sum\limits_{j=1}^{\lfloor \frac m d \rfloor } [gcd(i,j)==1]\\=\sum\limits_{d=1}^nf(d)\sum\limits_{e=1}^{\lfloor \frac n d \rfloor}\mu(e) \lfloor \frac n {de} \rfloor \lfloor \frac m {de} \rfloor\\=\sum\limits_{D=1}^{n}\sum\limits_{d|D}f(d)\mu(\frac D d) \lfloor \frac n {D} \rfloor \lfloor \frac m {D} \rfloor$

那么如果考虑a的限制呢?我们将所有询问离线,按a排序,然后从小到大处理所有询问,每处理到一个询问,就将所有f(d)<=a的d的贡献都统计出来。也就是说我们需要用某个数据结构来维护f*mu的前缀和,树状数组即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=100000;
typedef unsigned int ui;
int pri[N/10];
ui mu[N+10],f[N+10],s[N+10],ans[N];
int q[N+10];
int num,Q;
bool np[N+10];
struct node
{
	int n,m,a,org;
}p[N];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
bool cmp(const node &a,const node &b)
{
	return a.a<b.a;
}
bool cmpq(const int &a,const int &b)
{
	return f[a]<f[b];
}
inline void updata(int x,ui val)
{
	for(int i=x;i<=N;i+=i&-i)	s[i]+=val;
}
inline ui query(int x)
{
	ui ret=0;
	for(int i=x;i;i-=i&-i)	ret+=s[i];
	return ret;
}
int main()
{
	int i,j,k,last;
	mu[1]=1;
	for(i=2;i<=N;i++)
	{
		if(!np[i])	pri[++num]=i,mu[i]=-1;
		for(j=1;j<=num&&i*pri[j]<=N;j++)
		{
			np[i*pri[j]]=1;
			if(i%pri[j]==0)	break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(i=1;i<=N;i++)	for(j=i;j<=N;j+=i)	f[j]+=i;
	for(i=1;i<=N;i++)	q[i]=i;
	Q=rd();
	for(i=1;i<=Q;i++)
	{
		p[i].n=rd(),p[i].m=rd(),p[i].org=i;
		if(p[i].n>p[i].m)	swap(p[i].n,p[i].m);
		p[i].a=max(rd(),0);
	}
	sort(q+1,q+N+1,cmpq);
	sort(p+1,p+Q+1,cmp);
	for(i=j=1;i<=Q;i++)
	{
		for(;f[q[j]]<=p[i].a;j++)	for(k=q[j];k<=N;k+=q[j])	updata(k,f[q[j]]*mu[k/q[j]]);
		for(k=1;k<=p[i].n;k=last+1)
		{
			last=min(p[i].n/(p[i].n/k),p[i].m/(p[i].m/k));
			ans[p[i].org]+=(p[i].n/k)*(p[i].m/k)*(query(last)-query(k-1));
		}
	}
	for(i=1;i<=Q;i++)	printf("%u\n",ans[i]&0x7fffffff);
	return 0;
}
时间: 2024-11-08 22:55:27

【BZOJ3529】[Sdoi2014]数表 莫比乌斯反演+树状数组的相关文章

BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]

3529: [Sdoi2014]数表 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1399  Solved: 694[Submit][Status][Discuss] Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. Input 输入包含多组数据.    输入的第一行一个整数Q表示测试点内的数据

bzoj 3529 [Sdoi2014]数表 (莫比乌斯反演+树状数组+离线)

题目大意:有一张$n*m$的数表,第$i$行第$j$列的数是同时能整除$i,j$的所有数之和,求数表内所有不大于A的数之和 先是看错题了...接着看对题了发现不会做了...刚了大半个下午无果 看了Po姐的题解(Orzzz)才搞懂这道题,搞清楚了莫比乌斯反演的两种经典的卷积形式的不同之处 令$\sigma(i)$表示i的约数个数和 如果去掉A这个限制,则题目是让我们求$\sum_{i=1}^{n}\sum_{j=1}^{m}\sigma(gcd(i,j))$ 考虑如何正确转化式子,让我们能够把不大

【BZOJ3529】【莫比乌斯反演 + 树状数组】[Sdoi2014]数表

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

bzoj 3529 数表 莫比乌斯反演+树状数组

题目大意: 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. http://wenku.baidu.com/link?url=1zHluup-GXHdByoQXhMRwRu22Uu15y4DztIr1_hKVxjHJmuLQF4_01UQhLEOR7RJIpsGyfD_5fXrx9DE7sY6JeukaNUY83In097GjUOmZ7K ppt课件中讲的很仔细了 1

【莫比乌斯反演+树状数组+分块求和】GCD Array

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/I [题意] 给定长度为l的一个数组,初始值为0:规定了两种操作: [思路] 找到了一个讲解很清楚的博客http://www.cnblogs.com/flipped/p/HDU4947.html [Accepted] 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #inc

bzoj [SDOI2014]数表 莫比乌斯反演 BIT

bzoj [SDOI2014]数表 莫比乌斯反演 BIT 链接 bzoj luogu loj 思路 \[ \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}a*[f[gcd(i,j)]<=a] \] \[ f[]可以O(n)预处理出来 \] \[ \sum\limits_{k=1}^{n}f[k]*\sum\limits_{i=1}^{m}\sum\limits_{j=1}^{m}[gcd(i,j)==k] \] \[ \sum\limits_{k=1}^{n}

[SDOI2014]数表 莫比乌斯反演

---题面--- 题解: 设$f(d)$表示数$d$的约数和,那么$(i, j)$中的数为$f(gcd(i, j))$,那么有2种枚举方法.1,枚举每一格看对应的$f(d)$是几.$$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{m}{f(gcd(i, j))}$$2,枚举$d$看有哪些格子的$f$值为$f(d)$.$$ans = \sum_{i = 1}^{min(n, m)}{f(d)}\sum_{x = 1}^{n}\sum_{y = 1}^{m}[gcd(x,

BZOJ 3529([Sdoi2014]数表-莫比乌斯反演)

有一张N×m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和模2^31的值模2^31的值. 1<=n.m<=10 5 ,Q<=2×10 4  组询问 记k的约数和f(k) 求∑ n i=1 ∑ m j=1 gcd(i,j)[f(gcd(i,j))≤a] #include<bits/stdc++.h> using namespace std; #defin

[bzoj3529][Sdoi2014]数表_树状数组_莫比乌斯反演

数表 bzoj-3529 Sdoi-2014 题目大意:n*m的数表,第i行第j列的数是同时整除i和j的所有自然数之和.给定a,求数表中所有不超过a的和. 注释:$1\le n,m \le 10^5$. 想法:我们先不考虑那个a的限制:我们设f(i)表示整除i的自然数之和. $\sum\limits_{i=1}^n\sum\limits_{j=1}^m f(gcd(i,j))$ $\sum\limits_{i=1}^n\sum\limits_{j=1}^m f(d)\cdot [gcd(i,j)