【思维题】CodeForce 817B Makes And The Product

这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!

一、题目大意

现在发现codeforce的好处了,就是题目都比较简洁。这道题的大致意思是给你一个长度为N的数组a,然后让你找有多少个元组(i, j, k),使得a[i]*a[j]*a[k]最小。

二、题目思路以及AC代码

题目的意思很简单,我一开始想到的思路是桶排,毕竟这个叙述以及思路都太适合桶排了,当然桶排也确实可以很方便的解决这个问题,如果忽略这个题的数据范围。(哭)

这题给出的数组元素是1≤x≤1e9,桶排的话就需要4G的存储空间,肯定不行,所以就得另寻他法,然后我就想到,因为数组元素是正整数的,所以直接找最小的三个元素相乘肯定是最小的,但要考虑会有重复元素。

虽然有重复元素,但我们还是可以首先找到数组中数最小的三个元素,并且记录其在数组里出现的次数,然后最小值的出现次数大于3,假设为k,那么我们的结果就是在k个元素中选择3个,也就是组合数。如果最小值出现的次数是2,那么我们的结果就是在次小值出现的次数中选择1个;同理,如果最小值出现的次数是1,那么我们还得对次小值出现次数进行讨论,如果次小值出现次数大于等于2,那么结果就是在次小值出现次数中选择2个,而如果次小值出现次数等于1,那么我们的结果就是在第三小值的出现次数中选1个。

有了以上的分类讨论情况,接下来的代码也就很容易理解了。当然,这题有一个需要特别注意的点!也坑了我的,就是在算组合数的时候,由于给的N较大,所以会爆int,哎,我就是这么WA的。

下面给出AC代码:

#include <iostream>
#define INF 2147483647
using namespace std;

long long C[100005][4];

void get_C() {
	C[0][0] = 1;
	for (int i = 1; i <= 100000; i++) {
		C[i][0] = 1;
		for (int j = 1; j <= 3 && j <= i; j++) {
			C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
		}
	}
}

int main()
{
	get_C();

	int N;
	cin >> N;

	int min1 = INF, min2 = INF, min3 = INF;
	int cnt1 = 0, cnt2 = 0, cnt3 = 0;

	int num = 0;
	for (int i = 0; i < N; i++) {
		cin >> num;
		
		if (num < min1) {
			min3 = min2;
			cnt3 = cnt2;
			min2 = min1;
			cnt2 = cnt1;
			min1 = num;
			cnt1 = 1;
		}
		else if (num == min1){
			cnt1++;
		}
		else if (num < min2) {
			min3 = min2;
			cnt3 = cnt2;
			min2 = num;
			cnt2 = 1;
		}
		else if (num == min2) {
			cnt2++;
		}
		else if (num < min3) {
			min3 = num;
			cnt3 = 1;
		}
		else if (num == min3) {
			cnt3++;
		}
	}

	long long res = 0;
	
	if (cnt1 >= 3) {
		res = C[cnt1][3];
	}
	else if (cnt1 == 2) {
		res = C[cnt2][1];
	}
	else if (cnt2 >= 2) {
		res = C[cnt2][2];
	}
	else {
		res = C[cnt3][1];
	}

	cout << res << endl;

    return 0;
}

如果有问题,欢迎大家指正!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值