刷题:容斥原理 最大公约数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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现