lightOJ 1161 Extreme GCD(素数四元组)[容斥原理]
链接:lightOJ 1161
题意:给你
个数,选择其中四个数作为一组,使得这一组数的最大GCD为
,问你有多少组?
题解:这里用到容斥原理,先求逆问题,求GCD
的个数,然后用总值减去这个值。首先预处理出来因子包含
的数的个数,用
预存。对于GCD
的个数
,对于预处理因子
的时候,
的因子也会被预处理,那么在计算
的因子
的情况时,一定包含了
的情况,所以对求GCD
的个数的问题产生过一次贡献,在求
产生的贡献时,需要将其倍数减去,以免重复计算。例如对于
时,
,逆向递推,求到
的时候,即是GCD
的个数,分别存在
,然后用全部的减去这些值。即递推到
的情况(因为每个数都包含因子
,所以
)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e4+100;
int num[maxn];
void init_num(int x)
{
for(int i = 1; i <= x/i;i++)
{
if(x%i==0)
{
if(i*i==x)
{
num[i]++;
}
else
{
num[i]++;
num[x/i]++;
}
}
}
return ;
}
LL solve_C(int x)
{
LL ans = x;
ans = ans*(ans-1)*(ans-2)*(ans-3)/24;
return ans;
}
LL ans[maxn];
int main()
{
int t,cas = 0;
scanf("%d", &t);
while(t--)
{
int n,x;
int ma = 0;
scanf("%d", &n);
for(int i = 0; i<= 10010; i++)
{
num[i] = 0;
ans[i] = 0;
}
for(int i = 0; i < n; i++)
{
scanf("%d", &x);
ma = max(ma,x);
init_num(x);
}
for(int i = ma; i>=1;i--)
{
if(num[i]>=4)
{
ans[i] = solve_C(num[i]);
for(int j = 2*i; j <= ma;j+=i)
{
ans[i] -= ans[j];
}
}
}
printf("Case %d: %lld\n", ++cas,ans[1]);
}
return 0;
}