• Hdu 5072 Coprime(容斥+同色三角形)


    原题链接

    题意
    选出三个数,要求两两互质或是两两不互质。求有多少组这样的三个数。

    分析

    同色三角形
    n个点 每两个点连一条边(可以为红色或者黑色),求形成的三条边颜色相同的三角形的个数
    反面考虑这个问题,只需要c(n,3)减去不同色的三角形个数即可
    对于每一个点,所形成的不同色三角形即为 红色边的数量*黑色边的数量,所以可以O(n)地算出不同色三角形的个数(注意总数要除以2)
    然后用c(n,3)减一下即可

    对于这个题,如果把互质看作红色边,不互质看作黑色边,就可以转化为同色三角形问题了

    那如何求 互质的个数和不互质的个数呢?
    [可以参考一下这里]利用容斥原理求出每个数的不互质个数m,那么互质个数则为n-m-1。最终答案则为C(n,3)-m*(n-m+1)/2.
    预处理每个数的质因子,计算出每种质因子搭配的个数(表明n个数中有多少个为其倍数)num[].

    其他看代码:

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<vector>
    using namespace std;
    #define eps 1e-12
    #define inff 0x3fffffff
    #define nn 110000
    typedef __int64 LL;
    int n;
    int a[nn];
    int num[nn];
    vector<int>p[nn];
    bool use[nn];
    void init()
    {
        memset(use,false,sizeof(use));
        for(int i=2;i<=100000;i++)//分解质因子
        {
            if(!use[i])
            {
                for(int j=i;j<=100000;j+=i)
                {
                    p[j].push_back(i);
                    use[j]=true;
                }
            }
        }
    }
    int main()
    {
        int t,i,j,k;
        init();
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            memset(num,0,sizeof(num));
            int lv;
            int ix;
            for(i=1;i<=n;i++)//状压
            {
                if(a[i]==1)
                    continue;
                lv=p[a[i]].size();
                for(j=1;j<(1<<lv);j++)
                {
                    ix=1;
                    for(k=0;k<lv;k++)
                    {
                        if(((1<<k)&j))
                        {
                            ix*=p[a[i]][k];
                        }
                    }
                    num[ix]++;//表示n个数中为ix的倍数的个数
                }
            }
            int fc;
            LL tem;
            LL ans=0;
            LL m=n;
            for(i=1;i<=n;i++)
            {
                if(a[i]==1)
                    continue;
                lv=p[a[i]].size();
                tem=0;
                for(j=1;j<(1<<lv);j++)
                {
                    ix=1;
                    fc=0;
                    for(k=0;k<lv;k++)
                    {
                        if(((1<<k)&j))
                        {
                            ix*=p[a[i]][k];
                            fc++;
                        }
                    }
                    if(fc&1)
                    {
                        tem+=num[ix];
                    }
                    else
                        tem-=num[ix];
                }
                //tem-1才是与其不互质的个数,意思为减去自身
                ans+=(tem-1)*(m-tem);
            }
            ans/=2;
            ans=m*(m-1)*(m-2)/6-ans;
            printf("%I64d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    501. 二叉搜索树中的众数
    530. 二叉搜索树的最小绝对差
    Java强制类型转换注意
    PL_SQL常用快捷键及设置
    Java线程:大总结
    Java多线程售票程序分析
    Java多线程的几种实现方式
    Java线程的几种状态
    Java的同步机制:synchronized关键字
    Eclipse常用设置[不断完善]
  • 原文地址:https://www.cnblogs.com/fht-litost/p/7261066.html
Copyright © 2020-2023  润新知