洛谷 P3312 [SDOI2014]数表

题目链接


式中\(\sigma(d)=\sum\limits_{d'|d}{d'}\),这是个积性函数,可以欧拉筛\(O(n)\)求出来。

先不考虑\(a\)的限制,得

\(ans=\sum\limits_{i=1}^n{\sum\limits_{j=1}^m{\sigma({gcd(i,j))}}}\)

     \(=\sum\limits_{d=1}{ \sigma(d) \sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{m}{[gcd(i,j)=d]}}}\)

\(f(d)=\sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{m}{[gcd(i,j)=d]}}\)

\(F(d)=\sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{m}{[d \mid gcd(i,j)]}}\)

\(F(d)=\sum\limits_{d'}{f(d')}=\frac{n}{d} \cdot \frac{m}{d}\)

\(f(d)=\sum\limits_{d \mid d'}{\mu(\frac{d'}{d})F(d')}\)

\(\therefore ans=\sum\limits_{d=1}{\sigma(d)\sum\limits_{k=1}{\mu(k)\frac{n}{kd}\frac{m}{kd}}}\)

至此我们可以\(O(n)\)计算出\(ans\),对于\(a\)的限制,我们可以离线,将\(\sigma(d) \leq a\)的添加入树状数组中,分块时查询区间和。

然后。。。就\(T\)了。

所以我们要通过某种方式预处理,优化时间复杂度。

因为\(mn=10^{10}\),预处理不现实,我们对\(\sigma\)\(\mu\)预处理。

\(m\)\(n\)很烦人,把他们提到前面。

\(ans=\sum\limits_{T=1}{\frac{n}{T}\frac{m}{T}\sum\limits_{d\mid T}{\mu(\frac{T}{d})\sigma(d)}}\)

用树状树状储存\(\sum\limits_{d\mid T}{\mu(\frac{T}{d})\sigma(d)}\)这样我们每次加入\(\sigma(d)\)式就枚举\(d\)的倍数,加入树状数组中。

大家应该知道调和级数式\(O(logn)\)级别的吧。。。所以复杂度为\(O(nlog^2 n+q\sqrt n log n)\)

\(\frak{code:}\)

#include<bits/stdc++.h>
#define IL inline
#define LL unsigned int
using namespace std;
const int N=1e5+3;
const LL p=1u<<31;
struct que{
	int n,m,a,id;
	bool operator<(const que &b) const{
	return a<b.a;}
}q[N];
struct hh{
	LL val;int pos;
	bool operator<(const hh &a) const{
	return val<a.val;}
}b[N];
int n,m,num,t,now,mu[N],vis[N],pri[N],sum[N],Max[N];
LL s[N],ans[N],pre[N];
IL int in(){
	char c;int f=1;
	while((c=getchar())<'0'||c>'9')
	  if(c=='-') f=-1;
	int x=c-'0';
	while((c=getchar())>='0'&&c<='9')
	  x=x*10+c-'0';
	return x*f;
}
struct BIT{
	LL c[N];
	IL int lb(int x){return x&-x;}
	IL void add(int y,LL x){for(;y<N;y+=lb(y)) c[y]+=x;}
	IL LL ask(int y){LL res=0;for(;y;y-=lb(y)) res+=c[y];return res;}
}T;
IL void init(int n){
	mu[1]=s[1]=1;
	for(int i=2;i<=n;++i){
		if(!vis[i]){vis[i]=i,mu[i]=-1,pri[++pri[0]]=i,sum[i]=s[i]=i+1,Max[i]=i;}
		for(int j=1,k;(k=i*pri[j])<=n;++j){
			vis[k]=pri[j];
			if(i%pri[j]) sum[k]=pri[j]+1,s[k]=s[i]*sum[k],mu[k]=-mu[i],Max[k]=pri[j];
			else{
				Max[k]=Max[i]*pri[j],sum[k]=sum[i]+Max[k],
				s[k]=s[i]/sum[i]*sum[k];break;
			}
		}
	}
	for(int i=1;i<=n;++i) b[i]=(hh){s[i],i};
	sort(b+1,b+n+1);
}
IL LL solve(LL n,LL m){
	LL res=0;
	if(n>m) swap(n,m);
	for(LL l=1,r;l<=n;l=r+1){
		r=min(n/(n/l),m/(m/l));
		res+=(n/l)*(m/l)*(T.ask(r)-T.ask(l-1));
	}
	return res;
}
int main()
{
	init(1e5),t=in();
	for(int i=1;i<=t;++i) q[i]=(que){in(),in(),in(),i};
	sort(q+1,q+t+1);
	for(int i=1;i<=t;++i){
		while(b[now+1].val<=q[i].a&&now<1e5)
			for(int j=b[++now].pos,k=1;j<=1e5;j+=b[now].pos,++k) T.add(j,b[now].val*mu[k]); 
		ans[q[i].id]=solve(q[i].n,q[i].m)%p;
	}
	for(int i=1;i<=t;++i) printf("%u\n",ans[i]);
	return 0;
}
posted @ 2020-01-07 20:04  (o-ωq)).oO  阅读(130)  评论(0编辑  收藏  举报