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;
}





原文地址:https://www.cnblogs.com/mengfanrong/p/5062885.html