此类问题有两种解法,一种是二分,一种是优先队列
十日游戏
问两个数组各自任意选两数相乘或相加的值中前 n大的数
#include <bits/stdc++.h>
#define int long long
#define PII pair <int, int>
#define endl '\n'
#define sz(x) x.size()
#define lbt(x) (x)&(-x)
#define rep(i,n) for(int i=0;i<n;i++)
const int N = 2e5 + 10;
using namespace std;
typedef array<int, 3>ARR;
int a[N], b[N];
void solve() {
priority_queue<ARR>q;//这里懒得重载运算符了直接写的array
int n;
cin >> n;
for (int i = 1;i <= n;i++)cin >> a[i];
for (int i = 1;i <= n;i++)cin >> b[i];
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + n);
for (int i = 1;i <= n;i++)q.push({ a[i] + b[n],i,n });
while (n--) {
auto t = q.top();
q.pop();
int v = t[0], x = t[1], y = t[2];
cout << v << (n == 0 ? "\n" : " ");
if (y > 1)
q.push({ a[x] + (b[y - 1]),x,y - 1 });
}
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cout.tie(0);
int _ = 1;
while (_--)
solve();
return 0;
}
GDCPC广东省大学生程序设计竞赛 A An Easy Problem
从1 - n 中可重复的任取两数计算乘积,求所有结果中第k大的结果
优先队列解法
#include <bits/stdc++.h>
#define int long long
#define PII pair <int, int>
#define endl '\n'
#define sz(x) x.size()
#define lbt(x) (x)&(-x)
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
typedef array<int,3>ARR;
void solve() {
priority_queue<ARR>q;
int n, m, k;
cin >> n >> m >> k;
for (int i = 1;i <= n;i++)q.push({ i * m,i,m });
int res = 0;
while (k--) {
auto t = q.top();
res = t[0];
q.pop();
if (t[2] > 1) {
q.push({ t[1] * (t[2] - 1),t[1],t[2] - 1 });
}
}
cout << res << endl;
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cout.tie(0);
int _ = 1;
while (_--)
solve();
return 0;
}
二分解法
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define sz(x) x.size()
#define lbt(x) (x)&(-x)
#define all(x) x.begin(),x.end()
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
typedef pair<int, int> PII;
typedef double db;
const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f;
const db EPS = 1e-9;
int n, m, k;
bool check(int x) {
int tmp = 0;
for (int i = 1;i <= n;i++) tmp += min(m, x / i);
return tmp < k;
}
void solve() {
cin >> n >> m >> k;
k = n * m - k + 1;//转化为第k小的问题
int l = 1, r = 2e13;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid))l = mid;
else r = mid - 1;
}
cout << l + 1 << endl;
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cout.tie(0);
int _ = 1;
// cin >> _;
while (_--)
solve();
return 0;
}
小白月赛72 E顶级厨师
差不多的题意加了一些额外条件
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define sz(x) x.size()
#define lbt(x) (x)&(-x)
#define all(x) x.begin(),x.end()
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
typedef pair<int, int> PII;
typedef double db;
const int N = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f;
const db EPS = 1e-9;
void solve() {
int n, m, k, q;
cin >> n >> m >> k >> q;
vector<int>a(n), b(m), del;
for (auto& t : a)cin >> t;
for (auto& t : b)cin >> t;
while (k--) {
int u, v;
cin >> u >> v;
u--, v--;
del.push_back(a[u] * b[v]);
}
sort(all(a)), sort(all(b));
auto check = [&](int x, int t) {
int tmp = 0, r = b.size() - 1;
for (int i = 0;i < a.size();i++) {
while (r > -1 && a[i] * b[r] > x)r--;
tmp += r + 1;
}
for (auto tt : del) if (tt <= x)tmp--;
return tmp < t;
};
while (q--) {
int t;cin >> t;
int l = 0, r = 1e13;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid, t))l = mid;
else r = mid - 1;
}
cout << l + 1 << endl;
}
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cout.tie(0);
int _ = 1;
// cin >> _ ;
while (_--)
solve();
return 0;
}