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;
}