【莫比乌斯反演】[SDOI2014]数表

题目

∑ i = 1 n ∑ j = 1 m σ 1 ( g c d ( i , j ) ) [ σ 1 ( g c d ( i , j ) ) ≤ A ] \sum_{i=1}^n\sum_{j=1}^m\sigma_1(gcd(i,j))[\sigma_1(gcd(i,j))\leq A] i=1nj=1mσ1(gcd(i,j))[σ1(gcd(i,j))A]

题解

先不考虑A
∑ i = 1 n ∑ j = 1 m σ 1 ( g c d ( i , j ) ) ∑ d = 1 u p σ 1 ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ g c d ( i , j ) = = 1 ] ∑ d = 1 u p σ 1 ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ ∑ e ∣ g c d ( i , j ) μ ( e ) ∑ d = 1 u p σ 1 ( d ) ∑ e = 1 ⌊ u p d ⌋ μ ( e ) ⌊ n d e ⌋ ⌊ m d e ⌋ ∑ T = 1 u p ⌊ n T ⌋ ⌊ m T ⌋ ∑ d ∣ T σ 1 ( d ) μ ( T d ) \sum_{i=1}^n\sum_{j=1}^m\sigma_1(gcd(i,j))\\ \sum_{d=1}^{up}\sigma_1(d)\sum_{i=1}^{\lfloor\frac n d\rfloor} \sum_{j=1}^{\lfloor\frac m d\rfloor}[gcd(i,j)==1]\\ \sum_{d=1}^{up}\sigma_1(d)\sum_{i=1}^{\lfloor\frac n d\rfloor} \sum_{j=1}^{\lfloor\frac m d\rfloor}\sum_{e|gcd(i,j)}\mu(e)\\ \sum_{d=1}^{up}\sigma_1(d)\sum_{e=1}^{\lfloor\frac {up} d\rfloor}\mu(e) {\lfloor\frac n {de}\rfloor}{\lfloor\frac m {de}\rfloor}\\\sum_{T=1}^{up}{\lfloor\frac n {T}\rfloor}{\lfloor\frac m {T}\rfloor}\sum_{d|T}\sigma_1(d)\mu(\frac T d)\\ i=1nj=1mσ1(gcd(i,j))d=1upσ1(d)i=1dnj=1dm[gcd(i,j)==1]d=1upσ1(d)i=1dnj=1dmegcd(i,j)μ(e)d=1upσ1(d)e=1dupμ(e)dendemT=1upTnTmdTσ1(d)μ(dT)
f ( T ) = ∑ d ∣ T σ 1 ( d ) μ ( T d ) f(T)=\sum_{d|T}\sigma_1(d)\mu(\frac T d) f(T)=dTσ1(d)μ(dT)
最后考虑把A离线下来增量累加贡献,仅当 σ 1 ( d ) ≤ A \sigma_1(d)\leq A σ1(d)A有贡献
σ 1 \sigma_1 σ1按大小排序,每次累加可以产生贡献的 f ( d ) , f ( 2 d ) . . . f ( x d ) f(d),f(2d)...f(xd) f(d),f(2d)...f(xd)
需要用树状数组求前缀和以及单点修改
累加复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),询问 O ( l o g n ) O(logn) O(logn)
最后整除分块解决大柿子

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10,M=1e5;
const ll mod=1ll<<31;
struct qwq{
	int id;ll num;
	friend bool operator<(const qwq a,const qwq b){return a.num<b.num;}
}d[N];
int miu[N];
int z[N],p;
bool vis[N];
void Sieve()
{
	miu[1]=1;
	for(int i=2;i<=M;i++)
	{
		d[i].id=i;
		if(!vis[i])z[++p]=i,miu[i]=-1;
		for(int j=1;j<=p&&i*z[j]<=M;j++)
		{
			vis[i*z[j]]=1;
			if(i%z[j]==0)break;
			miu[i*z[j]]=-miu[i];
		}
	}
	for(int i=1;i<=M;i++)d[i].id=i;
	for(int i=1;i<=M;i++)
	for(int j=i;j<=M;j+=i)d[j].num+=i;
	sort(d+1,d+M+1);
}
ll t[N],key;
int lowbit(int x){return x&(-x);}
void add(int i){for(;i<=M;i+=lowbit(i))t[i]=(t[i]+key)%mod;}
ll qur(int i){ll ans=0;for(;i;i-=lowbit(i))ans=(ans+t[i])%mod;return ans;}
struct qus{
	int n,m,id;ll a;
	friend bool operator<(const qus x,const qus y){return x.a<y.a;}
}qs[N];
ll work(int n,int m)
{
	ll ans=0;int up=min(n,m);
	for(int l=1,r;l<=up;l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		ans=(ans+(n/l)*(m/l)%mod*(qur(r)-qur(l-1)+mod)%mod)%mod;
	}return ans;
}
ll ans[N];
int main()
{
	int T;Sieve();
	scanf("%d",&T);
	for(int i=1;i<=T;i++)
	scanf("%d%d%lld",&qs[i].n,&qs[i].m,&qs[i].a),qs[i].id=i;
	sort(qs+1,qs+T+1);
	ll pre=0;int pos=1;
	for(int i=1;i<=T;i++)
	{
		if(pre<qs[i].a)
		{
			pre=qs[i].a;
			while(d[pos].num<=pre&&pos<=M)
			{
				int x=d[pos].id;
				for(int j=x;j<=M;j+=x)
				{
					key=(d[pos].num*miu[j/x]%mod+mod)%mod;
					add(j);
				}
				pos++;
			}
		}
		ans[qs[i].id]=work(qs[i].n,qs[i].m);
	}
	for(int i=1;i<=T;i++)printf("%lld\n",ans[i]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值