HDU5072(容斥)

题目要求n个不同数中gcd两两为1或者两两不为1的三元对个数。

这是个单色三角形问题,大白105页有描述,主要要求对于每个数,其他的数中有几个数和它的gcd不是1。

坑点是会爆int,于是我一怒之下都改成了longlong~~~~

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
using namespace std;
#define maxn 111111

long long pr_cnt;
bool is_prime[maxn];
long long prime[maxn], cnt;
long long n, a[maxn], vis[maxn];
long long gg[maxn]; //和a[i]的gcd不为1的数的个数
long long kk[maxn]; //原数组中能被i整除数的个数
vector <int> fenjie[maxn];

void get_prime () {
    for (int i = 1; i <= 100000; i++) {
        fenjie[i].clear ();
    }
    memset (is_prime, 1, sizeof is_prime);
    is_prime[0] = is_prime[1] = 0;
    cnt = 0;
    for (int i = 2; i <= 100000; i++) {
        if (is_prime[i]) {
            prime[++cnt] = i;
            fenjie[i].push_back (i);
            for (int j = i+i; j <= 100000; j += i) {
                fenjie[j].push_back (i);
                is_prime[j] = 0;
            }
        }
    }
}

long long count (long long num, long long &mul, long long x) {
    mul = 1;
    long long ans = 0;
    for (int i = 1; i <= pr_cnt; i++, num >>= 1) {
        if (num&1) {
            ans++;
            mul *= fenjie[x][i-1];
        }
    }
    return ans;
}

void solve (long long num) { //cout << "num:" << num << endl;
    long long pre = num;
    pr_cnt = fenjie[num].size ();
    for (long long i = 1; i < (1<<pr_cnt); i++) {
        long long mul;
        long long num_of_1 = count (i, mul, pre);
        if (num_of_1&1) {
            gg[vis[pre]] += (kk[mul]-1);
        }
        else {
            gg[vis[pre]] -= (kk[mul]-1);
        }
    }
    return ;
}

int main () {
    get_prime (); 
    int t;
    scanf ("%d", &t);
    while (t--) {
        scanf ("%lld", &n); 
        memset (vis, 0, sizeof vis);
        memset (gg, 0, sizeof gg);
        memset (kk, 0, sizeof kk);
        for (int i = 1; i <= n; i++) {
            scanf ("%lld", &a[i]);
            vis[a[i]] = i;
        }
        for (int i = 2; i <= 100000; i++) {
            for (int j = i; j <= 100000; j += i) {
                if (vis[j])
                    kk[i]++;
            }
        }
        long long ans = 0;
        for (int i = 1; i <= n; i++) {
            solve (a[i]);
        }
        for (int i = 1; i <= n; i++)
            ans += gg[i]*(n-1-gg[i]);
        printf ("%lld\n", n*(n-1)*(n-2)/6 - ans/2);
    }
    return 0;
}


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