题目描述
难度分:1500
输入n(3≤n≤105)和长为n的数组a(1≤a[i]≤109)。
输出使a[i]×a[j]×a[k]最小且i<j<k的(i,j,k)三元组个数。
输入样例1
4
1 1 1 1
输出样例1
4
输入样例2
5
1 3 2 3 4
输出样例2
2
输入样例3
6
1 3 3 1 3 2
输出样例3
1
算法
排序+分类讨论
虽然题目里说要求i<j<k,但是我们并不关心(i,j,k)里面谁是谁,所以随便找出来一个三元组,让下标最小的充当i,次小的充当j,最大的充当k即可。又因为数组a中的数都是正数,所以最小的三数之积就是最小的三个数乘积。
对数组a排序,然后一个哈希表counter统计每个元素值的频数,再利用双指针算法对有序数组a去重。分情况讨论:
- 如果a[1]就已经不小于3个了,那最小积就是a[1]3,从counter[a[1]]个a[1]中选3个出来就行,方案数为C3counter[a[1]]。
- 如果a[1]和a[2]的频数不小于3个,假如a[1]只有一个,那选上这个a[1],再从counter[a[2]]个a[2]中选2个a[2],方案数为C2counter[a[2]]。假如a[1]有两个,那就选上这两个a[1],再从counter[a[2]]个a[2]中选1个a[2],方案数为C1counter[a[2]。
- 最后就是counter[a[1]]+counter[a[2]]+counter[a[3]]≥3的情况,那就前两个数都选上(前两个数都只有一个),从counter[a[3]]个a[3]中再选1个a[3]即可,方案数为counter[a[1]]×counter[a[2]]×counter[a[3]]。
复杂度分析
时间复杂度
排序的时间复杂度为O(nlog2n),后面的分类讨论都是O(1)的,因此整体的时间复杂度为O(nlog2n)。
空间复杂度
排序的空间复杂度以快排为基准,为O(log2n)。因此瓶颈在于开辟了一个哈希表存储数组a中元素值的频数,额外空间复杂度为O(n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <chrono>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, a[N];
struct custom_hash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + FIXED_RANDOM);
}
};
LL C3(int x) {
return (LL)x*(x - 1)*(x - 2)/6;
}
LL C2(int x) {
return (LL)x*(x - 1)/2;
}
int main() {
scanf("%d", &n);
unordered_map<int, int, custom_hash> counter;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
counter[a[i]]++;
}
sort(a + 1, a + n + 1);
int cnt = unique(a + 1, a + n + 1) - a - 1;
if(counter[a[1]] >= 3) {
printf("%lld\n", C3(counter[a[1]]));
}else if(counter[a[1]] + counter[a[2]] >= 3) {
LL ans = 0;
if(counter[a[1]] == 2) {
ans += (LL)C2(counter[a[1]])*counter[a[2]];
}else {
ans += (LL)counter[a[1]]*C2(counter[a[2]]);
}
printf("%lld\n", ans);
}else {
printf("%lld\n", (LL)counter[a[1]]*counter[a[2]]*counter[a[3]]);
}
return 0;
}