您的位置:首页 > 运维架构

Coprime HDU - 5072 单色三角形+莫比乌斯反演+容斥原理

2017-07-10 20:01 357 查看
单色三角形:如果每个人都有关系的话,认识或者不认识,随便找6个人(或以上),则一定会有三个人互相认识,或者互相不认识。因为每个人和其他人都有关系嘛,认识或者不认识。则一个人A与其他5个人有都有关系,这个时候当A与其他5个人的关系中有两个认识,3个不认识(或者2个不认识,3个认识)的时候组成的、

红边表示认识,蓝边表示不认识,这个时候组成的两边相同的三角形最少。



通过画图我们知道以A为顶点的两边颜色相同的至少有三对(假设为红)。如果三角形另外一条边为红的话,就证明了有三个人互相认识。如果颜色相同的那三对另外一条边都是蓝色的话,这个时候这三条蓝边也组成了一个蓝色三角形/doge,得证。

单色三角形模型是:有两种边,红色的和蓝色的,问你有多少单色三角形(三角形的三条边全是同一种颜色)。正着数有多少个单色三角形,不好数。所以我们采用减法原理,将总共的三角形数目-非单色三角形。那么非单色三角形怎么计算呢?每一个非单色三角形中肯定是有两条边不一样的,也就是说有来两个顶点连接的是不一样的边。如果这个顶点连接的是不一样的边的话,也就是说这个点连了ai条蓝边,(n-1-ai)红边。一共是ai*(n-1-ai)种方案,然后累加起来sum,因为一条边连着两个点,所以最后结果是 sum/2,用c(n,3)-sum/2 就行了

这个题的意思是,让你求三个点要么两两互质,要么两两不互质的数量。(就是求单色三角形的个数嘛,这里红边蓝边就变成了互不互质了)

用单色三角形的思想,我们对一个点来说,连一个互质和一个不互质的,为ai*(n-1-ai),ai表示与这个互质的个数,然后c(n,3)-sum/2 就行了

那么问题就转变成了怎么求与这个点互质的个数呢?如果暴力的话,就是n^2,n会达到 1e5,超时,用莫比乌斯反演? 那个不是1-n之间的么。然后我们这里用的是容斥原理的思想。对于每个数-和他有相同单个公因子数+相同双因子数-……..

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <vector>

using namespace std;
const int maxn = 1e5+10;
#define LL long long
int a[maxn];
int vis[maxn];
int miu[maxn];
int prime[maxn];
void mobious()
{
miu[1]=1;
int tot=0;
for(int i=2;i<=100000;i++)
{
if(!vis[i])
{
prime[tot++]=i;
miu[i]=-1;
}
for(int j=0;j<tot;j++)
{
int k=i*prime[j];
if(k>100000) break;
vis[k]=1;
if(i%prime[j]) miu[k]=-miu[i];
else break;
}
}
}
int maxx;
LL n;
LL hz[maxn],num[maxn];
void solve()
{
memset(num,0,sizeof(num));
memset(hz,0,sizeof(hz));
for(int i=1;i<=maxx;i++)
{
for(int j=i;j<=maxx;j+=i)//找是i个倍数的数量
num[i]+=vis[j];
for(int j=i;j<=maxx;j+=i)
hz[j]+=miu[i]*num[i];
}
LL ans=0;
for(int i=0;i<n;i++)
{
if(a[i]!=1)
{
ans+=(hz[a[i]]*(n-1-hz[a[i]]));
}
}
ans=n*(n-1)*(n-2)/6-ans/2;
printf("%I64d\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
mobious();
while(t--)
{
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
scanf("%I64d",&n);
maxx=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
vis[a[i]]++;
maxx=max(maxx,a[i]);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: