关于此题[ABC391F] K-th Largest Triplet 的一些总结
题目大意
- 给定三个序列,使得
,可以合并成 个元素的新序列,问此序列中第 大的元素是什么。
思路
发现题目给定的
- 第一种,直接二分答案。我们可以直接在
中二分答案,由于答案越大,新序列中比答案更大的数越少;答案越小,新序列中比答案更大的数越多。所以答案显然是具有单调性的。关键在于 函数怎么写,我们可以先让三个数组分别降序排序,然后依次枚举三个数组,记 表示 ,如果当前枚举到的 比枚举的答案大,那么就让计数器 加一,一旦 不小于给定的k,就直接返回真,表示答案还可能更大,否则返回假,表示答案只能更小。注意一个小剪枝:由于三个数组已经是从大到小排序的,所以在枚举的第一层循环中,如果 已经小于答案了,就可以直接break;在枚举的第二层循环中,如果 已经小于答案了,也可以直接break。由于至多枚举k次,所以整体复杂度应该是 ,其中m表示 ,不会超过100。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
long long t;
const long long N = 2e5 + 10;
long long n,k,a[N],b[N],c[N];
long long getnum(long long i,long long j,long long k) {
return a[i] * b[j] + a[i] * c[k] + b[j] * c[k];
}
bool check(long long x) {
long long cnt = 0;
for(long long i = 1;i <= n;i++) {
if(getnum(i,1,1) < x) break;
for(long long j = 1;j <= n;j++) {
if(getnum(i,j,1) < x) break;
for(long long z = 1;z <= n;z++) {
if(getnum(i,j,z) < x) break;
cnt++;
if(cnt >= k) return true;
}
}
}
return false;
}
void solve() {
cin >> n >> k;
for(long long i = 1;i <= n;i++) cin >> a[i];
for(long long i = 1;i <= n;i++) cin >> b[i];
for(long long i = 1;i <= n;i++) cin >> c[i];
sort(a + 1,a + 1 + n,greater<long long>());
sort(b + 1,b + 1 + n,greater<long long>());
sort(c + 1,c + 1 + n,greater<long long>());
long long l = 1,r = 9e18;
while(l < r) {
long long mid = (l + r) >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
if(r - l == 1) {
if(check(r)) l = r;
break;
}
}
cout << l;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// cin >> t;
t = 1;
while(t--) solve();
return 0;
}
- 第二种思路,“暴力”枚举。一样地,我们降序排列三个数组,并三个循环依次枚举
,放入一个储存数组中,最后再对储存数组找到第 大的数即可。只需要加一个小剪枝:当当前 已经大于k了,就可以直接break掉了(貌似很好理解),这样优化下来的时间复杂度是 。注意最后求第 大需要用nth_element()
,如果直接排序会超时。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
long long t;
const long long N = 2e6 + 10;
long long n,k,tot;
long long a[N],b[N],c[N];
vector<long long> cnt;
long long getnum(long long i,long long j,long long k) {
long long tmp = a[i] * b[j] + a[i] * c[k] + b[j] * c[k];
return tmp;
}
void solve() {
cin >> n >> k;
for(long long i = 1;i <= n;i++) cin >> a[i];
for(long long i = 1;i <= n;i++) cin >> b[i];
for(long long i = 1;i <= n;i++) cin >> c[i];
sort(a + 1,a + 1 + n,greater<long long>());
sort(b + 1,b + 1 + n,greater<long long>());
sort(c + 1,c + 1 + n,greater<long long>());
for(long long i = 1;i <= min(n,k);i++) {
for(long long j = 1;j <= min(n,k);j++) {
if(i * j > k) break;
for(long long z = 1;z <= min(n,k);z++) {
if(i * j * z > k) break;
cnt.push_back(getnum(i,j,z));
}
}
}
nth_element(cnt.begin(),cnt.begin() + k - 1,cnt.end(),greater<long long>());
cout << cnt[k - 1];
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
t = 1;
while(t--) solve();
return 0;
}
分类:
做题总结