SPOJ4191 POJ3904 Sky Code
10 May 2019 |
duanyll | Tags:
OI
题解
数论
容斥原理
最近学业繁忙,好久没有搞过OI了。。。
题意
给你n个数,现在让你求出有多少个四元组,满足这四个数的最大公约数等于1,$n \leq 10000$,$a_i \leq 10000$,多组询问,对于每个询问回答多少个四元组满足条件。
分析
用总方案数($C^{4}_{n}$)减去不合法方案数更容易。于是可以预处理出每一个$a_i$的取值包含多少个不同的质因子数,再看每个取值上有多少个原数组中的取值的因子(考虑每个取值作为四个数GCD的值)。最后统计时要排除有超过两个相同质因子的数,防止重复统计。
容斥原理是奇加偶减,这里因为是用总数减,变成奇减偶加。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long int64;
const int MAXN = 10010;
const int AMXA = 10000;
int64 C4(int64 n){
return n*(n-1)*(n-2)*(n-3) / 24;
}
int prime[MAXN];
bool isntp[MAXN];
int pcnt;
int pfac_cnt[MAXN];
void count_factor(){
for(int i = 2;i<=AMXA;i++){
if(!isntp[i]){
prime[pcnt++] = i;
pfac_cnt[i] = 1;
for(int j = i*2;j<=AMXA;j+=i){
isntp[j] = true;
if(j % (i*i) != 0 && pfac_cnt[j] != -1){
pfac_cnt[j]++;
}else{
pfac_cnt[j] = -1;
}
}
}
}
}
int a[MAXN];
int vcnt[MAXN];
int all_fac[MAXN];
int main(){
int n;
count_factor();
while(cin >> n){
memset(vcnt,0,sizeof vcnt);
memset(all_fac,0,sizeof all_fac);
for(int i = 1;i<=n;i++){
cin >> a[i];
vcnt[a[i]]++;
}
for(int i = 2;i<=AMXA;i++){
for(int j = i;j<=AMXA;j+=i){
all_fac[i] += vcnt[j];
}
}
int64 ans = C4(n);
for(int i = 2;i<=AMXA;i++){
if(pfac_cnt[i] > 0){
if(pfac_cnt[i] & 1){
ans -= C4(all_fac[i]);
}else{
ans += C4(all_fac[i]);
}
}
}
cout << ans << endl;
}
}