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


    http://acm.hdu.edu.cn/showproblem.php?pid=5072


    单色三角形模型


    现场赛和队友想了3个小时,最后发现想跑偏了。感觉好可惜的一道题,要是知道这个模型....就能够轻松的拿银了啊。

    题意不再赘述,就是求同色三角形的个数。总的三角形的个数是C(n,3),仅仅需减去不同色的三角形就可以。对于每一个点(数),与它互质的连红边,不互质的连蓝边,那么对于该点不同色三角形个数为蓝边数*红边数/2,由于同一个三角形被计算了两次。

    那么同色三角形个数为C(n,3) - ∑蓝边数*红边数/2。

    我们仅仅需求出蓝边数就能得知红边数。怎么求与该数不互质的数的个数?首先对原来的数质因子分解,把这些质因子的全部组合枚举出来,每一个质因子最多使用一次,得到若干个质因子的组合为ansNum,使用容斥原理,观察ansNum的质因子的个数。若是奇数就加上全部能被ansNum整数的数的个数。否则就减去。这样求出蓝边数。红边数也就已知了。


    #include <stdio.h>
    #include <iostream>
    #include <map>
    #include <set>
    #include <bitset>
    #include <list>
    #include <stack>
    #include <vector>
    #include <math.h>
    #include <string.h>
    #include <queue>
    #include <string>
    #include <stdlib.h>
    #include <algorithm>
    #define LL __int64
    //#define LL long long
    #define eps 1e-9
    #define PI acos(-1.0)
    using namespace std;
    const LL INF = 1<<30;
    const int maxn = 100010;
    
    int test;
    LL n;
    int a[maxn],num[maxn];
    int prime[maxn];
    bool flag[maxn];
    int fact[maxn][20];
    int coun[maxn];
    
    void getPrime()
    {
        memset(flag,0,sizeof(flag));
        flag[1] = true;
        prime[0] = 0;
        for(int i = 2; i < maxn; i++)
        {
            if(flag[i] == false)
                prime[++prime[0]] = i;
            for(int j = 1; j <= prime[0]&&i*prime[j] < maxn; j++)
            {
                flag[prime[j]*i] = true;
                if(i%prime[j] == 0)
                    break;
            }
        }
    }
    
    void getFact(int dig, int pos)
    {
    	int tmp = dig;
    
        for(int i = 1; i <= prime[0] && prime[i]*prime[i] <= tmp; i++)
        {
        	if(tmp % prime[i] == 0)
        	{
        		fact[pos][coun[pos]++] = prime[i];
        		while(tmp % prime[i] == 0)
    				tmp /= prime[i];
        	}
        	if(tmp == 1)
    			break;
        }
        if(tmp > 1)
    		fact[pos][coun[pos]++] = tmp;
    }
    
    void init()
    {
        for(int i = 2; i <= 100000; i++)
        {
            for(int j = i+i; j <= 100000; j += i)
                num[i] += num[j];
        }
    }
    
    
    int main()
    {
    	getPrime();
        scanf("%d",&test);
        while(test--)
        {
            memset(num,0,sizeof(num));
            scanf("%I64d",&n);
            for(int i = 1; i <= n; i++)
            {
                scanf("%d",&a[i]);
                num[a[i]]++;
            }
    
    		init();
    		memset(coun,0,sizeof(coun));
    
    		LL ans = 0;
    
    		for(int i = 1; i <= n; i++)
    		{
    			LL res = 0;
    			getFact(a[i], i);
    			for(int j = 1; j < (1<<coun[i]); j++)
    			{
    				LL ansNum = 1;
    				int cnt = 0;
    				for(int k = 0; k < coun[i]; k++)
    				{
    					if(j & (1<<k) )
    					{
    						ansNum *= fact[i][k];
    						cnt++;
    					}
    				}
    				if(cnt & 1)
    					res += (num[ansNum]-1);
    				else
    					res -= (num[ansNum]-1);
    			}
    			ans += (n-1-res)*res;
    		}
    		ans = n*(n-1)*(n-2)/6 - ans/2; //注意n为LL
    		printf("%I64d
    ",ans);
        }
        return 0;
    }
    
    
    



  • 相关阅读:
    手贱!使用django,在数据库直接删除了表
    js中在一个函数中引用另一个函数中的函数,可以这么做
    上传下载文件方式
    阻止form提交数据,通过ajax等上传数据
    一种思路,隐藏input标签,通过label关联
    java 寻找水仙花数
    java 统计素数个数问题
    java 兔子生仔问题
    java 实现读取某个目录下指定类型的文件
    通过java 来实现对多个文件的内容合并到一个文件中
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5062885.html
Copyright © 2020-2023  润新知