从给定的集合中求互质四元组的个数。
解题思路:先求解非互质四元组的个数,在总体四元组个数减去这个数目。求非互质四元组即求公因数大于1的四元组数目,因此,使用公因数d把集合中的元素划分成不同的子集,每个子集中的四元组一定是非互质的。还有一点需要考虑的是,不同子集中可能蕴含相同的非互质四元组。可以使用容斥原理解决这个问题,具体的方法是对公因数d进行质因数分解,若d可以分解成奇数个质数,就在非互质四元组总数中加上公因数d对应的非互质四元组,若为偶数则减去。
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int cnt[10010]; //记录每个因数对应子集的元素数
int num[10010]; //记录每个因数分解的不同质因数个数
int prime[5]; //记录一个数字对应的质因数(10000以内最多有五个不同质因数)
long long p[10010]={0}; //记录组合数
void solve(int n)
{
int tol=0;
for(int i=2;i*i<=n;i++) //求输入数字的质因数,方法很好
{
if(n%i==0)
prime[tol++]=i;
while(n%i==0)
n=n/i;
}
if(n!=1) //对应输入的数字本身就是质数
prime[tol++]=n;
for(int i=1;i<(1<<tol);i++) //质因数的组合方法有2的tol次幂个
{
int k=1,sum=0;
for(int j=0;j<tol;j++)
{
if(i&(1<<j)) //求一个具体的质因数组合,使用按位与方法
{
k=k*prime[j];
sum++;
}
}
cnt[k]++;
num[k]=sum;
}
}
int main()
{
int m,n;
long long i;
for(i=1;i<10010;i++)
p[i]=i*(i-1)*(i-2)*(i-3)/24;
while(cin>>n)
{
memset(cnt,0,sizeof(cnt));
for(i=0;i<n;i++)
{
cin>>m;
solve(m);
}
long long ans=0;
for(i=0;i<10010;i++)
{
if(cnt[i]>=4)
{
if(num[i]&1)
ans = ans+p[cnt[i]];
else
ans = ans-p[cnt[i]];
}
}
cout<<p[n]-ans<<endl;
}
return 0;
}
引自:http://www.voidcn.com/article/p-yddwtjwu-bda.html