【SDOI2014】数表【莫比乌斯反演】【树状数组】

传送门

传送门

题意:

T T T组询问给定 n , m , a n,m,a n,m,a,求

∑ i = 1 N ∑ j = 1 M [ ( ∑ d ∈ N ∗ [ d ∣ i ] [ d ∣ j ] d ) ≤ a ] ∑ d ∈ N ∗ [ d ∣ i ] [ d ∣ j ] d \sum_{i=1}^{N}\sum_{j=1}^{M}[(\sum_{d \in N^*}[d\mid i][d \mid j]d)\leq a]\sum_{d \in N^*}[d\mid i][d \mid j]d i=1Nj=1M[(dN[di][dj]d)a]dN[di][dj]d

1 ≤ n , m ≤ 1 e 5 , 1 ≤ a ≤ 1 e 9 , 1 ≤ T ≤ 2 e 4 1 \leq n,m \leq 1e5,1 \leq a \leq1e9,1 \leq T \leq2e4 1n,m1e5,1a1e9,1T2e4

2 31 2^{31} 231取模

反演神题

假设没有前面的限制

∑ i = 1 N ∑ j = 1 M ∑ d ∈ N ∗ [ d ∣ i ] [ d ∣ j ] \sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{d \in N^*}[d\mid i][d \mid j] i=1Nj=1MdN[di][dj]

F ( x ) F(x) F(x)表示约数和

∑ i = 1 N ∑ j = 1 M F ( g c d ( i , j ) ) \sum_{i=1}^N\sum_{j=1}^{M}F(gcd(i,j)) i=1Nj=1MF(gcd(i,j))

套路性地枚举 g c d gcd gcd

∑ d ∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = d ] F ( d ) \sum_{d}\sum_{i=1}^N\sum_{j=1}^{M}[gcd(i,j)=d]F(d) di=1Nj=1M[gcd(i,j)=d]F(d)

套路性地提到前面

∑ d F ( d ) ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] \sum_{d}F(d)\sum_{i=1}^n\sum_{j=1}^{m}[gcd(i,j)=d] dF(d)i=1nj=1m[gcd(i,j)=d]

后面是个套路性的反演

f ( d ) = ∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = d ] f(d)=\sum_{i=1}^N\sum_{j=1}^{M}[gcd(i,j)=d] f(d)=i=1Nj=1M[gcd(i,j)=d]

g ( d ) = ∑ d ∣ n f ( n ) = ⌊ N d ⌋ ⌊ M d ⌋ g(d)=\sum_{d\mid n}f(n)=\lfloor\frac{N}{d}\rfloor\lfloor\frac{M}{d}\rfloor g(d)=dnf(n)=dNdM

f ( d ) = ∑ d ∣ n g ( n ) μ ( n d ) = ∑ d ∣ n ⌊ N n ⌋ ⌊ M n ⌋ μ ( n d ) f(d)=\sum_{d\mid n}g(n)\mu(\frac{n}{d})=\sum_{d \mid n}\lfloor\frac{N}{n}\rfloor\lfloor\frac{M}{n}\rfloor\mu(\frac{n}{d}) f(d)=dng(n)μ(dn)=dnnNnMμ(dn)

代回去

∑ d F ( d ) ∑ d ∣ n ⌊ N n ⌋ ⌊ M n ⌋ μ ( n d ) \sum_{d}F(d)\sum_{d \mid n}\lfloor\frac{N}{n}\rfloor\lfloor\frac{M}{n}\rfloor\mu(\frac{n}{d}) dF(d)dnnNnMμ(dn)

∑ n = 1 m i n ( N , M ) ⌊ N n ⌋ ⌊ M n ⌋ ∑ d ∣ n F ( d ) μ ( n d ) \sum_{n=1}^{min(N,M)}\lfloor\frac{N}{n}\rfloor\lfloor\frac{M}{n}\rfloor\sum_{d\mid n}F(d)\mu(\frac{n}{d}) n=1min(N,M)nNnMdnF(d)μ(dn)

左边是个套路性的整除分块 不管

右边并没有很好的性质,只能筛出来暴力求……

等下,原题是有限制 F ( d ) ≤ a F(d)\leq a F(d)a

G ( n ) = ∑ d ∣ n F ( d ) μ ( n d ) G(n)=\sum_{d\mid n}F(d)\mu(\frac{n}{d}) G(n)=dnF(d)μ(dn)

我们发现只有不超过 a a a F ( d ) F(d) F(d)才对答案有贡献

T , N T,N T,N都很小

所以可以把 F ( d ) F(d) F(d) a a a排个序,拿个指针指一下

跑到一个 a a a把前面的 F ( d ) F(d) F(d)枚举倍数统计更新 G G G,再拿整除分块算答案

需要维护单点加,区间询问,用个树状数组即可

复杂度大概 O ( N l o g N + T l o g T T ) O(NlogN+TlogT\sqrt{T}) O(NlogN+TlogTT )

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 100005
using namespace std;
const int N=100000;
int np[MAXN],pl[MAXN],cnt;
int mu[MAXN],f[MAXN],mp[MAXN],pt[MAXN];
inline int qpow(int a,int p)
{
	int ans=1;
	while (p)
	{
		if (p&1) ans*=a;
		a*=a;p>>=1;
	}
	return ans;
}
void init()
{
	np[1]=mu[1]=f[1]=1;
	for (int i=2;i<=N;++i)
	{
		if (!np[i])
		{
			pl[++cnt]=i;
			mu[i]=-1;
			mp[i]=i;pt[i]=1;
		}
		int x;
		for (int j=1;(x=i*pl[j])<=N;++j)
		{
			np[x]=1;mp[x]=pl[j];
			if (i%pl[j]==0)
			{
				mu[x]=0;pt[x]=pt[i]+1;
				break;
			}
			mu[x]=-mu[i];pt[x]=1;
		}
	}
	for (int i=2;i<=N;i++)
	{
		int t=qpow(mp[i],pt[i]);
		if (i==t) f[i]=f[i/mp[i]]+t;
		else f[i]=f[t]*f[i/t];
	}
}
int p[MAXN];
inline bool cmp(const int& a,const int& b){return f[a]<f[b];}
struct query{int n,m,a,id;}q[MAXN];
inline bool operator <(const query& x,const query& y){return x.a<y.a;}
struct BIT
{
	int s[MAXN];
	inline int lowbit(const int& x){return x&-x;}
	inline void modify(int x,const int& v){for (;x<=N;s[x]+=v,x+=lowbit(x));}
	inline int query(int x){int ans=0;for (;x;ans+=s[x],x-=lowbit(x));return ans;}
}g;
int res[MAXN];
//int calc(int x,int y,int a)
//{
//	int ans=0;
//	for (int i=1;i<=x&&i<=y;i++)
//		if (x%i==0&&y%i==0)
//			ans+=i;
//	if (ans<=a) return ans;
//	else return 0;
//}
int main()
{
	init();
	for (int i=1;i<=N;i++) p[i]=i;
	sort(p+1,p+N+1,cmp);
	int pos=0;
	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;
//		int t=0;
//		for (int x=1;x<=q[i].n;x++)
//			for (int y=1;y<=q[i].m;y++)
//				t+=calc(x,y,q[i].a);
//		printf("%d\n",t&(~(1<<31)));
	}
	sort(q+1,q+T+1);
	for (int i=1;i<=T;i++)
	{
		while (pos<N&&f[p[pos+1]]<=q[i].a)
		{
			++pos;
			for (int d=1;d*p[pos]<=N;++d) g.modify(d*p[pos],f[p[pos]]*mu[d]);
		}
		if (q[i].n>q[i].m) swap(q[i].n,q[i].m);
		int ans=0;
		for (int l=1,r;l<=q[i].n;l=r+1)
		{
			r=min(q[i].n/(q[i].n/l),q[i].m/(q[i].m/l));
			ans+=(q[i].n/l)*(q[i].m/l)*(g.query(r)-g.query(l-1));
		}
		res[q[i].id]=ans;
	}
	for (int i=1;i<=T;i++) printf("%d\n",res[i]&(~(1<<31)));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值