P3327 [SDOI2015]约数个数和(思维+莫比乌斯反演)

题目传送门
这是一个很有意思的莫反
这道题要你求
∑ i = 1 n ∑ j = 1 m d ( i j ) \displaystyle\sum_{i=1}^{n}\displaystyle\sum_{j=1}^{m}d(ij) i=1nj=1md(ij)
d ( ) d() d()表示约数的个数

这里有一个结论需要记住就是:
d ( i , j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(i,j)=\displaystyle\sum_{x|i}^{}\displaystyle\sum_{y|j}^{}[gcd(x,y)=1] d(i,j)=xiyj[gcd(x,y)=1]
具体证明就是:按情况分类,因数个数就是分情况考虑
如果 i j ij ij中包含 a k a^k ak那么在这两个 ∑ ∑ 中就是枚举了 k + 1 k+1 k+1 a 0 a^0 a0(也就是一次都没有枚举过,也算一次),因为毕竟是因数和函数,性质我们都不好搞,所以搞一个比较熟悉的 g c d gcd gcd

那么这个式子就是:
∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] \displaystyle\sum_{i=1}^{n}\displaystyle\sum_{j=1}^{m}\displaystyle\sum_{x|i}^{}\displaystyle\sum_{y|j}^{}[gcd(x,y)=1] i=1nj=1mxiyj[gcd(x,y)=1]通过莫比乌斯反演我们可以知道

∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j ∑ d ∣ g c d ( x , y ) μ ( d ) \displaystyle\sum_{i=1}^{n}\displaystyle\sum_{j=1}^{m}\displaystyle\sum_{x|i}^{}\displaystyle\sum_{y|j}^{}\displaystyle\sum_{d|gcd(x,y)}^{}μ(d) i=1nj=1mxiyjdgcd(x,y)μ(d)
交换枚举顺序
∑ d = 1 m i n ( n , m ) μ ( d ) ∑ i = 1 n / d ∑ j = 1 m / d ∑ x ∣ i ∑ y ∣ j \displaystyle\sum_{d=1}^{min(n,m)}μ(d)\displaystyle\sum_{i=1}^{n/d}\displaystyle\sum_{j=1}^{m/d}\displaystyle\sum_{x|i}^{}\displaystyle\sum_{y|j}^{} d=1min(n,m)μ(d)i=1n/dj=1m/dxiyj
继续交换枚举顺序
∑ d = 1 m i n ( n , m ) μ ( d ) ∑ x = 1 n / d ∑ y = 1 m / d ∑ i = 1 n / ( d ∗ x ) ∑ j = 1 m / ( d ∗ y ) \displaystyle\sum_{d=1}^{min(n,m)}μ(d)\displaystyle\sum_{x=1}^{n/d}\displaystyle\sum_{y=1}^{m/d}\displaystyle\sum_{i=1}^{n/(d*x)}\displaystyle\sum_{j=1}^{m/(d*y)} d=1min(n,m)μ(d)x=1n/dy=1m/di=1n/(dx)j=1m/(dy)
然后得到
∑ d = 1 m i n ( n , m ) μ ( d ) ∑ x = 1 n / d ∑ y = 1 m / d [ n d ∗ x ] [ m d ∗ y ] \displaystyle\sum_{d=1}^{min(n,m)}μ(d)\displaystyle\sum_{x=1}^{n/d}\displaystyle\sum_{y=1}^{m/d}[\frac{n}{d*x}][\frac{m}{d*y}] d=1min(n,m)μ(d)x=1n/dy=1m/d[dxn][dym]
再进行分离,为啥?因为你前后无瓜!
∑ d = 1 m i n ( n , m ) μ ( d ) ( ∑ x = 1 n / d [ n d ∗ x ] ) ( ∑ y = 1 m / d [ m d ∗ y ] ) \displaystyle\sum_{d=1}^{min(n,m)}μ(d)(\displaystyle\sum_{x=1}^{n/d}[\frac{n}{d*x}])(\displaystyle\sum_{y=1}^{m/d}[\frac{m}{d*y}]) d=1min(n,m)μ(d)(x=1n/d[dxn])(y=1m/d[dym])
看这个东西:
( ∑ y = 1 m / d [ m d ∗ y ] ) (\displaystyle\sum_{y=1}^{m/d}[\frac{m}{d*y}]) (y=1m/d[dym])
t = m / d t=m/d t=m/d那不就成了
( ∑ y = 1 t [ t y ] ) (\displaystyle\sum_{y=1}^{t}[\frac{t}{y}]) (y=1t[yt])
对这个进行数论分块,预处理一下

for(ll i=1;i<=N;i++)
{
	for(ll l=1,r;l<=i;l=r+1)
	{
	  	r=i/(i/l);
	  	check[i]+=(r-l+1)*(i/l);
	}
}

因为到最后枚举的是 n d ∗ x \frac{n}{d*x} dxn
有前面的一个 d d d这个问题
所以还要再进行一个数论分块(因为数组访问的,你每回计算的角标有大量的相等的情况)

#include<iostream>
using namespace std;
typedef long long ll;
const ll N = 50005;
ll check[N+5];
ll mu[N + 5], p[N + 5];
bool flg[N + 5];
void mobius() {
	  ll tot = 0;
	  mu[1] = 1;
	  for (ll i = 2; i <= N; ++i) {
	    if (!flg[i]) {
	      p[++tot] = i;
	      mu[i] = -1;
	    }
	    for (ll j = 1; j <= tot && i * p[j] <= N; ++j) {
	      flg[i * p[j]] = 1;
	      if (i % p[j] == 0) {
	        mu[i * p[j]] = 0;
	        break;
	      }
	      mu[i * p[j]] = -mu[i];
	    }
	  }
	  //数论分块要用到的前缀和 
	  for (ll i = 1; i <= N; ++i) mu[i] += mu[i - 1];
	  for(ll i=1;i<=N;i++){
	  	for(ll l=1,r;l<=i;l=r+1){
	  		r=i/(i/l);
	  		check[i]+=(r-l+1)*(i/l);
	  		
		  }//cout<<check[i]<<endl;
	  		//if(i==50)exit(0);
	  }
}
int main(){
	mobius();
	int T;
	cin>>T;
	while(T--){
		ll n,m,ans=0;
		cin>>n>>m;
		for(ll l=1,r;l<=min(m,n);l=r+1){
		//	cout<<check[l]<<" "<<l<<endl;
			r=min(m/(m/l),n/(n/l));
			ans+=(mu[r]-mu[l-1])*(check[m/l])*check[n/l];
		//	cout<<ans<<endl;
		}
		cout<<ans<<endl;
	} 
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值