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

Posted shurak

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj3529][Sdoi2014]数表_树状数组_莫比乌斯反演相关的知识,希望对你有一定的参考价值。

数表 bzoj-3529 Sdoi-2014

题目大意:n*m的数表,第i行第j列的数是同时整除i和j的所有自然数之和。给定a,求数表中所有不超过a的和。

注释:$1le n,m le 10^5$。

想法:我们先不考虑那个a的限制:我们设f(i)表示整除i的自然数之和。

$sumlimits_{i=1}^nsumlimits_{j=1}^m f(gcd(i,j))$

$sumlimits_{i=1}^nsumlimits_{j=1}^m f(d)cdot [gcd(i,j)==d]$

$sumlimits_{d=1}^n f(d)sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{m}{d} floor}[gcd(i,j)==1]$

$sumlimits_{d=1}^n f(d)sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sumlimits_{e|i,e|j} mu(e)$

$sumlimits_{d=1}^n f(d)sumlimits_{e=1}^{lfloorfrac{n}{d} floor}mu(e)sumlimits_{i=1}^{lfloorfrac{n}{de} floor}sumlimits_{j=1}^{lfloorfrac{m}{de} floor}$

$sumlimits_{D=1}^n sumlimits_{d|D} f(d)cdot mu(frac{D}{d})sum(lfloorfrac{n}{D} floor)sum(lfloorfrac{m}{D} floor)$

然后,显然$f$函数是积性函数,$mu$函数是积性函数,所以$f$和$mu$的狄利克雷卷积$fcdot mu$是积性函数,所以不限制的问题就解决了。

那我们考虑限制怎么办?其实也非常简单。我们只需要在树状数组上维护出小于a的f,查询即可。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 2147483647
using namespace std;
typedef long long ll; 
const int N=100010;
int mu[N],e[N],ans[N],c[N],vis[N],p[N],t[N],g[N];
struct F{int d,num;}f[N];
struct Q{int n,m,a,id;}q[N];
inline bool cmpT(Q a,Q b){return a.a<b.a;}
inline bool cmpt(F a,F b){return a.d<b.d;}
inline int lowbit(int x){return x&-x;}
int power(int a,int b)
{
	int res=1;
	while(b)
	{
		if (b&1) res*=a;
		a*=a;
		b>>=1;
	}
	return res;
}
void add(int x,int val)
{
	for(int i=x;i<N;i+=lowbit(i)) c[i]+=val;
}
int query(int x)
{
	int s=0;
	for(int i=x;i;i-=lowbit(i)) s+=c[i];
	return s;
}
int main()
{
	mu[1]=1;f[1].d=f[1].num=1;
	for(int i=2;i<N;i++)
	{
		f[i].num=i;
		if(!vis[i]) mu[i]=-1,f[i].d=t[i]=1+i,g[i]=1,p[++p[0]]=i;
		for(int j=1;j<=p[0] && i*p[j]<N;j++)
		{
			vis[i*p[j]]=1;
			if(i%p[j]==0)
			{
				mu[i*p[j]]=0;
				g[i*p[j]]=g[i]+1;
				t[i*p[j]]=t[i]+power(p[j],g[i]+1);
				f[i*p[j]].d=f[i].d/t[i]*t[i*p[j]];
				break;
			}
			else
			{
				mu[i*p[j]]=-mu[i];
				f[i*p[j]].d=f[i].d*f[p[j]].d;
				g[i*p[j]]=1;t[i*p[j]]=p[j]+1;
			}
		}
	}
	int T; scanf("%d",&T);
	for(int i=1;i<=T;i++) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].id=i;
	sort(q+1,q+1+T,cmpT);
	sort(f+1,f+N,cmpt);
	for(int now=0,i=1;i<=T;i++)
	{
		while(now+1<N && f[now+1].d<=q[i].a)
		{
			now++;
			for(int j=1;j*f[now].num<N;j++)
			{
				add(j*f[now].num,mu[j]*f[now].d);
			}
		}
		int n=q[i].n,m=q[i].m;
		if(n>m) swap(n,m);
		for(int j=1,k;j<=n;j=k+1)
		{
			k=min(n/(n/j),m/(m/j));
			ans[q[i].id]+=(n/j)*(m/j)*(query(k)-query(j-1));
		}
		ans[q[i].id]&=inf;
	}
	for(int i=1;i<=T;i++) printf("%d
",ans[i]);
	return 0;
}

小结:这就是典型的拟对象的题,我们通过先构造拟对象,然后向完全对象转化,非常巧妙。

以上是关于[bzoj3529][Sdoi2014]数表_树状数组_莫比乌斯反演的主要内容,如果未能解决你的问题,请参考以下文章

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

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

bzoj3529[Sdoi2014]数表 莫比乌斯反演+离线+树状数组

bzoj3529: [Sdoi2014]数表

bzoj3529 Sdoi2014—数表

[BZOJ3529][SDOI2014]数表