Light OJ -1161 Extreme GCD (容斥)

All of you know that GCD means the greatest common divisor. So, you must have thought that this problem requires finding some sort of GCD. Don’t worry, you are absolutely right!

Given N positive integers, not necessarily distinct, how many ways you can take 4 integers from the N numbers such that their GCD is 1.

Input
Input starts with an integer T (≤ 20), denoting the number of test cases.

Each case starts with an integer N (4 ≤ N ≤ 10000). The next line contains N integers separated by spaces. The integers will be positive and not greater than 10000.

Output
For each case, print the case number and the number of ways you can take the integers as mentioned above.

Sample Input
3
4
2 4 6 1
5
1 2 4 6 8
10
12 46 100 131 5 6 7 8 9 10
Sample Output
Case 1: 1
Case 2: 4
Case 3: 195

题意

给n个数,问 从中选出四个数他们的gcd 是1 的方案有多少种。

思路

1.首先直接算方案数感觉很复杂,所以我们可以考虑算方案数的补集。比如说我知道有x个数是2的倍数 那么C(x,4) 这些方案数的gcd就不是1 而是2。那么我们可以轻松的算出那些gcd不是1的方案,然后用总的C(n,4)减去即可。
2.其次需要考虑去重。
举个例子,6是2 的倍数 也是3的倍数 也是6的倍数如果一些数,既是2 的倍数也是 6的倍数那么我在减的时候 就会将这些方案减很多次。 所以我在减去2的倍数的方案时,需要2的倍数的方案里不包含6的倍数的方案。那么这就变成了一个递推的过程(或者说是容斥)具体见代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
long long ans[10005];
long long f[10005];
long long C(long long n){
    return n*(n-1)*(n-2)*(n-3)/24;
}
void js(int x){
    for(int i=1;i*i<=x;i++){
        if(x % i==0){
            f[i]++;
            if(i*i!=x){
                f[x/i]++;
            }
        }
    }
}
int main(){
    freopen("in.txt","r",stdin);
    int T,cas=0,n,x;
    scanf("%d",&T);
    while(T--){
        printf("Case %d: ",++cas);
        scanf("%d",&n);
        memset(f,0,sizeof f);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            js(x);
        }
        for(int i=10000;i>=1;i--){
            ans[i]=C(f[i]);
            for(int j=i*2;j<=10000;j+=i)
                ans[i]-=ans[j];
        }
        printf("%lld\n",ans[1]);

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值