zoukankan      html  css  js  c++  java
  • hdu5072-Coprime(容斥原理)

    题意:给N个互不相同的数,选择出两两互质或者两两不互质的三个数,有多少种选法。

    题解:一共有C(N,3)中选择方式,减去不符合要求的,剩下的就是答案。

    详见 http://blog.csdn.net/csuhoward/article/details/44978087

    看到有的题解说是同色三角形,感觉和CCPC长春那个六个人三个人必有互相认识或者互相不认识好像= =

    开始求出了所有质数的组合,然后一直T,后来看题解发现只要对现有的数做预处理就可以=。=

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    typedef long long ll;
    
    const int N = 100005;
    int a[N], n;
    int fac[N][10], sz[N];
    int ret[N];
    int vis[N];
    
    int prime[N], p;
    bool is_prime[N];
    
    int sieve()
    {
        for (int i = 0; i < N; ++i) is_prime[i] = true;
        is_prime[0] = is_prime[1] = false;
        for (int i = 2; i < N; ++i) {
            if (is_prime[i]) {
                prime[p++] = i;
                for (int j = 2 * i; j <= n; j += i)
                    is_prime[j] = false;
            }
        }
        return p;
    }
    
    void init() {
        int cnt, x, limit;
        for (int i = 1; i <= 100000; ++i) {
            x = i, limit = sqrt(x), cnt = 0;
            for (int k = 0; prime[k] <= limit; ++k) {
                if (x % prime[k] == 0) fac[i][cnt++] = prime[k];
                while (x % prime[k] == 0) x /= prime[k];
            }
            if (x > 1) fac[i][cnt++] = x;
            sz[i] = cnt;
        }
    }
    
    ll solve() {
        memset(ret, 0, sizeof ret);
        for (int i = 1; i < N; ++i) {
            for (int j = i; j < N; j += i) {
                if (vis[j]) ret[i]++;
            }
        }
    
        ll ans = 0;
        for (int i = 0; i < n; ++i) {
            int cnt = sz[a[i]];
            int st = 1<<cnt;
            ll tmp = 0;
            for (int k = 1; k < st; ++k) {
                int val = 1;
                int w = 0;
                for (int j = 0; j < cnt; ++j) {
                    if (k & (1<<j)) {
                        val *= fac[a[i]][j];
                        w ^= 1;
                    }
                }
                if (w) tmp += ret[val]-1;
                else tmp -= ret[val]-1;
            }
            ans += tmp * (n-tmp-1);
        }
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        sieve();
        init();
        while (T--) {
            scanf("%d", &n);
            memset(vis, 0, sizeof vis); // everyone has unique id
            for (int i = 0; i < n; ++i) scanf("%d", &a[i]), vis[a[i]] = 1;
            ll ans = solve();
            ll tot = (ll)n * (n-1) * (n-2) / 6;
            printf("%lld
    ", tot - ans/2);
        }
        return 0;
    }
  • 相关阅读:
    用位运算求一个数的绝对值
    ORACLE临时表总结
    Nagios学习实践系列——配置研究[监控当前服务器]
    SQL SERVER 作业浅析
    超酷的测速网站Ookla SPEEDTEST
    Nagios学习实践系列——基本安装篇
    Nagios学习实践系列——产品介绍篇
    Windows Server 2008 下ASP程序连接ORACLE数据库驱动错误
    ORACLE基本数据类型总结
    Redhat Server 5.7 安装配置PHP
  • 原文地址:https://www.cnblogs.com/wenruo/p/5962277.html
Copyright © 2011-2022 走看看