P2714 四元组统计

题目描述

\(n\)个正整数\(a_i\),你要统计有多少个四元组满足\(\mathrm{gcd}(a_i,a_j,a_k,a_l) = 1\)

题解

这道题思路很显然,就是枚举\(gcd\)的思路。

我们用\(f[x]\)表示\(x\)以及\(x\)的倍数的出现次数,输入时先把该数的出现次数统计了,然后可以\(O(n*ln\ n)\)加上他的倍数的出现次数。

然后考虑答案的计算。

如果\(gcd\)\(x\)或者\(x\)的倍数的话,方案数显然是\(\frac{f[x] * (f[x] - 1) * (f[x] - 2) * (f[x] - 3)}{24}\)(由于同一种选择随意排列有\(4!=24\)种情况,所以除以\(24\))。

那么转化成\(gcd\)\(x\)的方案数,我们就需要简单容斥一下,减去\(gcd\)\(2*x,3*x...k*x\)的方案数,所以我们倒着循环,就可以再次在\(O(n*ln\ n)\)的时间统计了。

#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int N = 1e4 + 5;
int mx, n;
ll f[N];
inline int read()
{
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void work()
{
	while(scanf("%d", &n) != EOF)
	{
		for(int i = 1; i <= mx; i ++) f[i] = 0; mx = 0;
		for(int i = 1, x; i <= n; i ++) {x = read(); f[x] ++; mx = max(mx, x);}
		for(int i = 1; i <= mx; i ++) for(int j = 2 * i; j <= mx; j += i) f[i] += f[j];
		for(int i = mx; i >= 1; i --)
		{
			f[i] = f[i] * (f[i] - 1) * (f[i] - 2) * (f[i] - 3) / 24;
			for(int j = 2 * i; j <= mx; j += i) f[i] -= f[j];
		}
		printf("%lld\n", f[1]);
	}
}
int main() {return work(), 0;}

猜你喜欢

转载自www.cnblogs.com/Sunny-r/p/12599717.html