SEERC 2008 Problem B Sky Code

POJ 3904

题目大意

在N(N <= 10000)个正整数里、找出gcd(p1, p2, p3, p4) == 1 的所有组合个数 pi <= 10000.

解题思路

  1. 求出<=10000的所有素数并保存
  2. 求出所有 m=p1 * p2 * p3 * p4 的数 (pi为素数且p1 < p2 < p3 < p4, m <= 10000) 
  3. 根据容斥原理 ANS = C(N,4) - C(g2, 4) - C(g3,4) - ... - C(gp,4) + C(g23, 4) + C(g25, 4) + ...  - C(g235, 4) - C(g237, 4) ....

其中g2表示N个数字里%2==0的个数,g23表示%(2 * 3)==0的个数,C(N,M)为组合数。

Example

需要测试数据的同学可以留言

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		new Main().start();
	}

	private long cn4(int n) {
		if (n < 4)
			return 0;
		long ret = n;

		ret *= (ret - 1) * (ret - 2) * (ret - 3);
		return ret / 24;
	}

	int[] p = new int[2000];
	int tp;
	int[] odd = new int[10001];

	private int find(int m) {
		int ret = 0;
		for (int i = 0; i < tp && m >= p[i] * p[i]; i++) {
			if (m % p[i] == 0) {
				m /= p[i];

				if (m % p[i] == 0) {
					return -1;
				}
				ret++;
			}
		}
		if (m != 1) {
			ret++;
		}
		return ret & 1;
	}

	private void start() {
		Scanner in = new Scanner(System.in);

		int n;
		int[] a = new int[10000];

		tp = 0;
		p[tp++] = 2;
		for (int i = 3; i < 10000; i += 2) {
			if (isP(i)) {
				p[tp++] = i;
			}
		}
		for (int i = 2; i <= 10000; i++) {
			odd[i] = find(i);
		}

		while (in.hasNextInt()) {
			n = in.nextInt();
			long ans = cn4(n);
			int max = 0;
			for (int i = 0; i < n; i++) {
				a[i] = in.nextInt();
				max = Math.max(a[i], max);
			}
			for (int i = 2; i * 4 <= max; i++) {
				if (odd[i] == -1)
					continue;
				int s = 0;
				for (int j = 0; j < n; j++) {
					if (a[j] % i == 0) {
						s++;
					}
				}
				long tmp = cn4(s);
				if (odd[i] == 1) {
					ans -= tmp;
				} else {
					ans += tmp;
				}
			}
			System.out.println(ans);
		}

	}

	private boolean isP(int m) {
		for (int i = 3; i * i <= m; i += 2) {
			if (m % i == 0) {
				return false;
			}
		}
		return true;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值