2024初秋集训——提高组 #27
B. 抉择
题目描述
给定 \(N\) 个数 \(A_1,A_2,\dots,A_N\),求一个 \(A\) 的子序列 \(B\) 的 \(\sum \limits_{i=1}^{k-1} B_i \operatorname{AND} B_{i+1}\) 的最大值。
思路
令 \(dp_i\) 表示最后一个数是 \(A_i\) 的最大答案。我们很明显有转移 \(dp_i\leftarrow dp_j+A_j \operatorname{AND} A_i\)。
贪心地思考,我们肯定要使子序列的长度尽可能长。所以我们肯定会从尽可能近的地方转移过来。所以我们对于每一位求出上次出现的位置并转移即可。
空间复杂度 \(O(N)\),时间复杂度 \(O(N\log \max\{A_i\})\)。
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 1000001;
const ll INF = (ll)(1e18);
int n;
ll a[MAXN], dp[MAXN], last[41], ans;
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> a[i];
for(int j = 0; j <= 40; ++j) {
dp[i] = max(dp[i], dp[last[j]] + (a[last[j]] & a[i]));
if((a[i] >> j) & 1) {
last[j] = i;
}
}
ans = max(ans, dp[i]);
}
cout << ans;
return 0;
}
C. 重生
题目描述
你有 \(N\) 个任务,第 \(i\) 个任务需要 \(t_i\) 天。你的一次生命有 \(c\) 天。你可以对一个任务进行深入思考,使得需要时间减 \(d_i\) 天,但你在一次生命中对一个任务只能思考一次。如果需要天数 \(\le 0\) 则无需时间便可解决。你可以复活,每次复活会再给你一次生命,之前深入思考的结果不会丢失。在最后一次生命之前你不能做任务,只能思考。求至少要复活多少次。
思路
二分需要复活的次数 \(x\)。我们把任务按 \(d_i\) 从大到小排序,显然我们必然优先把 \(d_i\) 大的进行思考。
但是对于最后一次思考要特殊处理,因为最后一次思考要不然是在最后一条命进行的,要么是再思考就降为 \(0\)。这里我们对最后一次的减少天数从大到小排序,然后一个一个做直到次数不够了位置,最后判断是否能做完即可。
空间复杂度 \(O(N)\),时间复杂度 \(O(N\log N\log \sum t_i)\)。
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
const int MAXN = 200001;
struct Node {
ll t, d;
}s[MAXN];
int T, n, c;
bool check(ll x) {
ll sum = 0, cnt = 0, tc = c;
vector<pii> ve;
for(int i = 1; i <= n; ++i) {
sum += s[i].t;
ll v = min(x, s[i].t / s[i].d);
sum -= v * s[i].d;
cnt += v;
if(s[i].t - v * s[i].d) {
ve.emplace_back(min(s[i].d, s[i].t - v * s[i].d), v == x);
}
}
sort(ve.begin(), ve.end(), [](const pii &a, const pii &b) -> bool {
return a.first > b.first;
});
for(auto [a, b] : ve) {
if(cnt >= (__int128)(x + 1) * c) {
break;
}
sum -= a;
tc -= b;
cnt++;
}
return sum <= min((__int128)tc, (__int128)(x + 1) * c - cnt);
}
ll Binary_Search() {
ll l = 0, r = (ll)(3e14);
for(; l < r; ) {
ll mid = (l + r) >> 1;
(check(mid) ? r = mid : l = mid + 1);
}
return l;
}
void Solve() {
cin >> n >> c;
for(int i = 1; i <= n; ++i) {
cin >> s[i].t >> s[i].d;
}
sort(s + 1, s + n + 1, [](const Node &a, const Node &b) -> bool {
return a.d > b.d;
});
cout << Binary_Search() << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
for(cin >> T; T--; Solve()) {
}
return 0;
}