刷题:容斥原理 最大公约数gcd

2023.11.28 cf上的1900D

容斥原理

  先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。

 

本题思路

  由本题数据不难看出暴力枚举肯定超时。

  先对数组排序,再在其中找出gcd值为x以及x的倍数的所有三元组相加。

  由容斥原理,在最后只需要从f(x)中减去f(2x)、f(3x)......,得到的结果就是gcd三元组中值为x的个数,再乘以x即为相应的贡献,贡献相加即为答案。

 

预处理的时间复杂度

  预处理中的时间复杂度为O(nlogn),并且形如

for (int i = 1;i <= n;i++)//调和级数
	for (int j = 1;j <= n/i;j++) ...

  的时间复杂度都是O(nlogn)

 

代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
vector<int> b[100005];
int a[80005];
ll c[100005],f[100005];
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	for(int i=1;i<=100000;i++)
	{
		for(int j=i;j<=100000;j+=i)
		{
			b[j].push_back(i);//预处理一个数的所有因数
		}
	}
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		memset(c,0,sizeof(c));
		memset(f,0,sizeof(f));
		ll ans=0;
		cin>>n;
		for(int i=1;i<=n;i++)cin>>a[i];
		sort(a+1,a+1+n);
		for(int i=1;i<=n;i++)
		{
			for(auto x:b[a[i]])//计算x以及x倍数的三元组个数之和
			{
				f[x]+=c[x]*(n-i);
				c[x]++;
			}
		}
		for(int i=100000;i>=1;i--)
		{
			for(int j=2*i;j<=100000;j+=i)
			{
				f[i]-=f[j];//容斥原理
			}
			ans+=f[i]*i;
		}
		cout<<ans<<endl;
	}
	return 0;
}
posted @   modemingzi  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示