zoukankan      html  css  js  c++  java
  • ACM学习历程—HDU 5072 Coprime(容斥原理)

    Description

    There are n people standing in a line. Each of them has a unique id number. 

    Now the Ragnarok is coming. We should choose 3 people to defend the evil. As a group, the 3 people should be able to communicate. They are able to communicate if and only if their id numbers are pairwise coprime or pairwise not coprime. In other words, if their id numbers are a, b, c, then they can communicate if and only if [(a, b) = (b, c) = (a, c) = 1] or [(a, b) ≠ 1 and (a, c) ≠ 1 and (b, c) ≠ 1], where (x, y) denotes the greatest common divisor of x and y. 

    We want to know how many 3-people-groups can be chosen from the n people.

     

    Input

    The first line contains an integer T (T ≤ 5), denoting the number of the test cases. 

    For each test case, the first line contains an integer n(3 ≤ n ≤ 10 5), denoting the number of people. The next line contains n distinct integers a1, a 2, . . . , a n(1 ≤ a i ≤ 10 5) separated by a single space, where a i stands for the id number of the i-th person.

     

    Output

    For each test case, output the answer in a line.

     

    Sample Input

    1

    5

    1 3 9 10 2

     

    Sample Output

    4

    题目大意是在n个数里面取出三个数a, b, c,如果三者两两互质或者两两都不互质就加入计算。求总的取法数。

    首先这两种情况都比较难算,于是考虑补集,其中有且仅有两个互质或者不互质。

    这两种情况发现有个共同特征,就是有一个互质且有一个不互质,另外一种关系就随便了。

    这样的话就是对于每一个a,计算和它互质的乘上和它不互质的。

    但是这样还是有问题的:

    因为对于如果(a, b) = 1 && (a, c) != 1,那么如果(b, c) = 1,发现对于数c,同样满足a的条件。

    所以对于每一个数都会被计算两次,也就是每一个三元组都被计入了两次,最后结果需要除以2。

    接下来就是解决如何计算对于一个a,和a互质以及不互质的数个数。

    首先如果可以枚举a的质因子的话,比如p,那么所有p的倍数都是与a不互质的。

    但是如果对于q,也加上q的倍数的话,会出现重复,就是pq的倍数被计算了两次。

    所以这里计算的时候需要进行容斥。

    考虑到这里的话,就不需要枚举a的因子了,只需要枚举所有数找倍数,用容斥判断这里的倍数个数是加还是减, 还是没有贡献。这里的容斥我用莫比乌斯系数完成的。

    最后用C(n, 3)-ans/2即可。

     

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <set>
    #include <queue>
    #include <vector>
    #define LL long long
    
    using namespace std;
    
    const int maxN = 100005;
    int n, d[maxN], top;
    LL f[maxN];
    int prime[maxN], u[maxN], cnt;
    bool vis[maxN];
    
    void mobius()
    {
        memset(vis, false,sizeof(vis));
        u[1] = 1;
        cnt = 0;
        for(int i = 2; i < maxN; i++)
        {
            if(!vis[i])
            {
                prime[cnt++] = i;
                u[i] = -1;
            }
            for(int j = 0; j < cnt && (LL)i*prime[j] < maxN; j++)
            {
                vis[i*prime[j]] = true;
                if(i%prime[j])
                    u[i*prime[j]] = -u[i];
                else
                {
                    u[i*prime[j]] = 0;
                    break;
                }
            }
        }
    }
    
    void input()
    {
        memset(d, 0, sizeof(d));
        scanf("%d", &n);
        int tmp;
        top = 0;
        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &tmp);
            d[tmp]++;
            top = max(top, tmp);
        }
    }
    
    void work()
    {
        LL ans = 0;
        int num;
        memset(f, 0, sizeof(f));
        for (int i = 2; i <= top; ++i)
        {
            num = 0;
            for (int j = i; j <= top; j += i)
                num += d[j];
            for (int j = i; j <= top; j += i)
                f[j] += u[i]*(1-num);
        }
        for (int i = 0; i <= top; ++i)
            ans += d[i]*f[i]*(n-f[i]-1);
        ans = (LL)n*(n-1)*(n-2)/6-ans/2;
        printf("%I64d
    ", ans);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        mobius();
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            input();
            work();
        }
        return 0;
    }
  • 相关阅读:
    MFC子窗体、父窗体
    私有云计算安全问题不容忽视
    云计算更多的是一种模式而不是技术
    原型模式向量的原型
    企业发票异常分析分离进项与销项
    考试系统框架搭建
    抽象工厂模式人与肤色
    工厂方法模式加密算法
    简单工厂模式女娲造人
    企业发票异常分析导入,清洗
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4907408.html
Copyright © 2011-2022 走看看