HDU 5072 Hackthon (容斥 同色三角形变形)

题意:

给出几个数字,求选出的数全部互质或全不互质的种数

 

解题思路:

同色三角形原理,一个平面上有n个点,两个点之间可能是红线,也可能是连黑线,问一共能连出多少个同色三角形?

从一个点出发,有n-1条线,假设红线有的d[ i ]条,黑线有n-1-d[ i ]条,那么从这一点出发不同色的三角形个数为d[ i ]*(n-1-d[ i ])个,所以总的不同色三角形个数为sum = d[ i ]*(n-1-d[ i ])  (i=1,2,3...n),所以同色三角形的个数是c(n,3)-sum/2(因为每条边用了两次,也就是说一个三角形被计算了两次,除以二)

 

这题类似的,将两个互质的数看作黑边,不互质的数看作红边,计算方法同上

那么主要要解决的就是判断两个数是否互质,这一块用容斥解决

先将100000以内的数打表,保存到prime[ ]这个数组中去

分别求出n个数的质因子,奇数个相乘的用+,偶数个用-     <===   这个地方用了容斥的方法,不懂可以调试一下

 

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
using namespace std;
#define LL __int64
const int maxn = 100010;
int test;
LL n;
int a[maxn],num[maxn],k;
int prime[maxn];
bool flag[maxn];
int fact[maxn][20];
int coun[maxn];
void getprime()
{
	memset(flag,0,sizeof(flag));
	flag[1] = true;
	prime[0]=0;
	k=0;
	for(int i=2;i<maxn;i++)
	{
		if(flag[i]==0) prime[++k] = i;
		for(int j=i;j<maxn;j+=i)
		{
			flag[j]=1;
		}
	}
}
void init()
{
	for(int i=2;i<=100000;i++)
	{
		for(int j=i+i;j<=100000;j+=i)
		{
			num[i]+=num[j];
		}
	}
}
void getFact(int dig,int pos)
{
	int tmp = dig;
	for(int i=1;i<=k && i*i<=tmp;i++)
	{
		if(tmp%prime[i]==0)
		{
			fact[pos][coun[pos]++]=prime[i];
			while(tmp%prime[i]==0)
			{
				tmp/=prime[i];
			}
		}
		if(tmp==1) break;
	}
	if(tmp!=1) fact[pos][coun[pos]++]=tmp;
}
int main()
{
	getprime();
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(num,0,sizeof(num));
		scanf("%I64d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			num[a[i]]++;
		}
		init();
		memset(coun,0,sizeof(coun));
		LL ans=0;
		for(int i=1;i<=n;i++)
		{
			LL res=0;
			getFact(a[i],i);
			for(int j=1;j<(1<<coun[i]);j++)
			{
				LL ansNum = 1;
				int cnt = 0;
				for(int k=0;k<coun[i];k++)
				{
					if(j&(1<<k))
					{
						ansNum *= fact[i][k];
						cnt++;
					}
				}
				if(cnt&1) res+=(num[ansNum]-1);
				else res-=(num[ansNum]-1);
			}
			ans+=(n-1-res)*res;
		}
		ans = n*(n-1)*(n-2)/6-ans/2;//n,ans要用LL 
		printf("%I64d\n",ans);
	}
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值