Loading

[SDOI2014]数表

链接:https://www.luogu.com.cn/problem/P3312

题目描述:求\(\sum_{i=1}^{n}\sum_{j=1}^{m}d(gcd(i,j))[d(gcd(i,j))<=a]\)

题解:我们先会有一个直观的想法:先不考虑\(a\)的限制:

\(\qquad\sum_{i=1}^{n}\sum_{j=1}^{m}d(gcd(i,j))\)

\(\quad=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|gcd(i,j)}d\)

\(\quad=\sum_{d=1}^{n}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\)

如果你这么推就推不下去了。

考虑换一种思路,将\(d\)看作一个不能拆开的函数:

\(\qquad\sum_{i=1}^{n}\sum_{j=1}^{m}d(gcd(i,j))\)

\(\quad=\sum_{t=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==t]d(t)\)

\(\quad=\sum_{t=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{t}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{t}\rfloor}[gcd(i,j)==1]d(t)\)

\(\quad=\sum_{t=1}^{n}d(t)\sum_{i=1}^{\lfloor\frac{n}{t}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{t}\rfloor}\sum_{s|gcd(i,j)}μ(s)\)

\(\quad=\sum_{t=1}^{n}d(t)\sum_{s=1}^{n}μ(s)\lfloor\frac{n}{ts}\rfloor\lfloor\frac{m}{ts}\rfloor\)

\(\quad=\sum_{T=1}^{n}\sum_{t|T}d(t)μ(\frac{T}{t})\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\)

我们可以将所有数按\(d(x)\)的值排序,将询问也按\(a\)排序,用树状数组处理贡献即可。

#include<iostream>
#include<algorithm> 
#define N 100000
using namespace std;
struct node
{
	long long x,y,a,num;
	bool operator < (const node &t)const
	{
		return a<t.a;
	}
};
struct reads
{
	long long num,data;
	bool operator < (const reads &a)const
	{
		return data<a.data;
	}
};
node query[1000001];
reads top[1000001];
long long c[1000001],res,f[1000001],miu[1000001],mod;
unsigned long long ans[1000001];
bool prime[1000001];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y)
{
	for (;x<=N;x+=lowbit(x))
		c[x]+=y;
	return;
}
long long sum(int x)
{
	res=0;
	for (;x>=1;x-=lowbit(x))
		res+=c[x];
	return res;
}
void prework()
{
	for (int i=1;i<=N;++i)
		miu[i]=1;
	for (int i=2;i<=N;++i)
		if (!prime[i])
			for (int j=i;j<=N;j+=i)
			{
				prime[j]=1;
				if ((j/i)%i==0)
					miu[j]=0;
				miu[j]=-miu[j];
			}
	for (int i=1;i<=N;++i)
		for (int j=i;j<=N;j+=i)
			f[j]+=i;
	for (int i=1;i<=N;++i)
	{
		top[i].num=i;
		top[i].data=f[i];
	}
	sort(top+1,top+N+1);
	return;
}
int main()
{
	prework();
	int t,pos=0,last;
	mod=(1ll<<31);
	cin>>t;
	for (int i=1;i<=t;++i)
	{
		cin>>query[i].x>>query[i].y>>query[i].a;
		query[i].num=i;
	}
	sort(query+1,query+t+1);
	for (int q=1;q<=t;++q)
	{
		while (pos<N&&top[pos+1].data<=query[q].a)
		{
			pos++;
			for (int i=top[pos].num;i<=N;i+=top[pos].num)
				add(i,top[pos].data*miu[i/top[pos].num]);
		}
		for (int i=1;i<=min(query[q].x,query[q].y);i=last+1)
		{
			last=min(query[q].x/(query[q].x/i),query[q].y/(query[q].y/i));
			ans[query[q].num]=(ans[query[q].num]+(query[q].x/i)*(query[q].y/i)%mod*(sum(last)-sum(i-1))%mod)%mod;
		}
	}
	for (int q=1;q<=t;++q)
		cout<<ans[q]<<endl; 
	return 0;
}
posted @ 2022-12-14 21:27  zhouhuanyi  阅读(30)  评论(0)    收藏  举报