【luogu P2714】四元组统计(高维前缀和 / 差分)

四元组统计

题目链接:luogu P2714

题目大意

给你 n 个数,问你有多少个四元组满足它们四个的 gcd 为 1。

思路

考虑到我们是要 gcd ⁡ \gcd gcd 1 1 1,那就是要每个质数每个数的出现个数的最小值都是 0 0 0
考虑一个类似容斥的过程,就是我们可以求 f i f_i fi 表示有多少个数至少都是 i i i 的倍数。(这个直接高维前缀和)

那你求出个数 x x x 之后直接变成 ( x 4 ) \Large\binom{x}{4} (4x),然后你这个部分还要容斥,那你可以莫反(所以其实你可以不用高维前缀和而是把莫反 μ \mu μ 不是 0 0 0 的位置只求这些好像也可以过还很快)。
也可以直接高维差分。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long

using namespace std;

const int N = 1e4 + 100;
int n, a[N], m, prime[N];
bool np[N];
ll f[N];

void Init() {
	for (int i = 2; i < N; i++) {
		if (!np[i]) prime[++prime[0]] = i;
		for (int j = 1; j <= prime[0] && i * prime[j] < N; j++) {
			np[i * prime[j]] = 1; if (i % prime[j] == 0) break;
		}
	}
}

int main() {
	Init();
	
	while (scanf("%d", &n) != EOF) {
		m = 0; for (int i = 1; i <= n; i++) scanf("%d", &a[i]), m = max(m, a[i]);
		for (int i = 1; i <= m; i++) f[i] = 0; for (int i = 1; i <= n; i++) f[a[i]]++;
		
		for (int i = 1; i <= prime[0] && prime[i] <= m; i++)//高维前缀和
			for (int j = m / prime[i]; j >= 1; j--)
				f[j] += f[j * prime[i]];
		for (int i = 1; i <= m; i++) f[i] = f[i] * (f[i] - 1) * (f[i] - 2) * (f[i] - 3) / 4 / 3 / 2;//乘上组合数
		for (int i = 1; i <= prime[0] && prime[i] <= m; i++)//高维差分
			for (int j = 1; j * prime[i] <= m; j++)
				f[j] -= f[j * prime[i]];
		printf("%lld\n", f[1]);
	}
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值