hdu 5072 Coprime(容斥)

hdu 5072 Coprime


数学容斥的首杀,借鉴了不少人的博客
题意:在一维数组中找出三个数使得两两互质或者两两不互质的方案数。
用总的方案数减去三个数中 至少含有一对互质一对非互质 的情况就是最后答案。
假设a为当前基点,与a至少含有一个公因子的数的个数为B,那么必有(N-1-B)个数与a互质;
为了求出B,显然不能一个个排查,否则会超时。
可以用F[i]表示全局中含有因子i的情况(i的质因子数为g(i)),利用容斥定理进行按j的奇偶性进行累加。其中,i具有一些特殊性:将i分解质因子后所得表达式中每项的指数为1。不然会增加额外的运算时间。
容斥定理按g(i)的奇偶性累加的规则为:
if(g(i)为奇数) +F[i]
else -F[i]
因为 F[ii] = (F[ia] ∩ F[ib] ∩ F[ic]....)|| null  而且 { g(ia)==g(ib)==g(ic)....==g(ii)-1 }
#include <stdio.h>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <cmath>
using namespace std;
#ifdef __GNUC__
typedef long long LL;
#define opt64(a) printf("%lld",a);
#else
typedef __int64 LL;
#define opt64(a) printf("%I64d",a);
#endif // __GNUC__
const int MAXN = 100000;
const double eps = 1e-8;
const double PI = acos(-1.0);
int prime[MAXN+5], np = 0;
int vis[MAXN+5], n, len[MAXN], fac[100];
int aa, ee;
vector<int> ls[MAXN];
void divide(int x, int &c)
{
    int k;
    c = 0;
    for (int i = 0; i<np; ++i)
    {
        k = prime[i];
        if (k*k > x) break;
        if (x % k == 0)
        {
            fac[c++] = k;
            while (x%k==0) x/=k;
        }
    }
    if (x != 1)
        fac[c++] = x;
}
void dfs(int x, int dx)
{
    if (dx == ee)
    {
        if (x != 1)
            ls[aa].push_back(x);
        return;
    }
    dfs(x,dx+1);
    dfs(x*fac[dx], dx+1);
}
void init_prime()
{
    for (int i = 2; i<= MAXN; ++i)
    {
        if (!vis[i]) prime[np++] = i;
        for (int j = 0; j< np && prime[j]*i <= MAXN; ++j)
        {
            vis[prime[j]*i] = 1;
            if (prime[j] % i == 0) break;
        }
    }
    for (int i = 2; i<= MAXN; ++i)
    {
        divide(i, len[i]);
        aa = i; ee = len[i];
        dfs(1,0);
    }
}
int cnt[MAXN+5], sf[MAXN+5];
LL solve()
{
    LL res = LL(n)*(n-1)*(n-2)/6;
    LL ap = 0LL;
    int as;
    for (int i = 2; i<= MAXN; ++i)
    {
        if (!cnt[i]) continue;
        for (int j = 0, k=ls[i].size(); j<k; ++j)
        {
            sf[ls[i][j]] += cnt[i];
        }
    }
    for (int i = 2; i<= MAXN; ++i)
    {
        if (!cnt[i]) continue;
        as = 0;
        for (int j = 0, k=ls[i].size(), c; j<k; ++j)
        {
            c = ls[i][j];
            if (len[c] & 1)
                as += sf[c] - 1;
            else
                as -= sf[c] - 1;
        }
        ap += LL(as)*(n-1-as);
    }
    return res - (ap>>1);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int t;
    scanf("%d", &t);
    init_prime();
    while (t--)
    {
        scanf("%d", &n);
        memset(cnt, 0, sizeof cnt);
        memset(sf, 0, sizeof sf);
        for (int i = 1; i<= n; ++i)
        {
            int num;
            scanf("%d", &num);
            ++cnt[num];
        }
        opt64(solve());
        puts("");
    }
    return 0;
}


你可能感兴趣的:(容斥)