P1447 [NOI2010] 能量采集(容斥原理)

题目链接:点击这里

题目大意:
给定 n , m n,m n,m ∑ i = 1 n ∑ j = 1 m 2 gcd ⁡ ( i , j ) − 1 \sum_{i=1}^n\sum_{j=1}^m2\gcd(i,j)-1 i=1nj=1m2gcd(i,j)1

题目分析:
这个题可以通过反演求解,但我们换一种思路,从容斥原理的角度除法
f x f_x fx 表示 gcd ⁡ ( i , j ) = x \gcd(i,j)=x gcd(i,j)=x 的数对个数,此时问题就转化成了求 ∑ ( 2 x − 1 ) f x \sum (2x-1)f_x (2x1)fx ,直接求这个函数不太好求我们考虑间接求该函数值
g x g_x gx 表示 x x x ( i , j ) (i,j) (i,j) 公因数的数对个数,那么显然 g x = ( n / x ) × ( m / x ) g_x=(n/x)\times(m/x) gx=(n/x)×(m/x)
有了 g x g_x gx 后我们就可以通过容斥原理把 x x x 2 , 3 , . . . 2,3,... 2,3,... 倍删掉,即 f x = g x − ∑ i = 2 i x ≤ m i n ( n , m ) f i f_x=g_x-\sum_{i=2}^{ix\le min(n,m)}f_i fx=gxi=2ixmin(n,m)fi
这样我们就可以倒着枚举求解 f x f_x fx ,边求解边维护答案即可,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn) (调和级数)

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<string>
#define int long long
using namespace std;
const int maxn = 1e5+5;
int n,m,ans,f[maxn];
signed main()
{
	cin>>n>>m;
	for(int i = n;i;i--)
	{
		f[i] = (n/i)*(m/i);
		for(int j = 2;i*j <= n;j++) f[i] -= f[i*j];
		ans += (2*i-1)*f[i];
	}
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值