AcWing 231. 天码 (容斥)打卡

题目:https://www.acwing.com/problem/content/233/

题意:给你n个不同的数,让你选取一个四元组,gcd为1,让你求这样的四元组数量是多少

思路:我们单独直接去算肯定不行,正难反易,我们可以用总的减去其他gcd不是1的,也就是四个数同时有一个相同且不是1的因子,然后我们按gcd值分组

但是中间有很多分组其实有重复的值,比如  2,3  那么 6就是他们重复的,这个题不能n^2过,我们只能拆每个数的因子,然后用这些因子构造出其他与当前

数构造出不是1因子的个数

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#define MAX_N 100005
#define MAX_FACTOR 16

int n, f[MAX_N];
int count[MAX_N];
int factor[MAX_FACTOR];
int prime_fac_num[MAX_N];

void input()
{
    for (int i = 0; i < n; i++)
        scanf("%d", &f[i]);
}

void make(int a)
{
    int factor_cnt = 0;
    for (int i = 2; i * i <= a; i++)
        if (a % i == 0)
        {
            factor[factor_cnt++] = i;
            while (a % i == 0)
                a /= i;
        }
    if (a > 1)
        factor[factor_cnt++] = a;
    for (int i = 1; i < (1 << factor_cnt); i++)
    {
        int used_fac = 0;
        int cur_fac = 1;
        for (int j = 0; (i >> j) > 0; j++)
        {
            if ((i >> j) & 1)
            {
                used_fac++;
                cur_fac *= factor[j];
            }
        }
        count[cur_fac]++;
        prime_fac_num[cur_fac] = used_fac;
    }

}

long long cal(long long a)
{
    return a * (a - 1) * (a - 2) * (a - 3) / 24;
}

int main()
{
    while (scanf("%d", &n) != EOF)
    {
        input();
        memset(count, 0, sizeof(count));
        memset(prime_fac_num, 0, sizeof(prime_fac_num));
        for (int i = 0; i < n; i++)
            make(f[i]);
        long long ans = cal(n);
        for (int i = 2; i <= 10000; i++)
        {
            if (prime_fac_num[i] & 1)
                ans -= cal(count[i]);
            else
                ans += cal(count[i]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Lis-/p/11296638.html