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;
}
posted @ 2024-09-28 17:47  Yaosicheng124  阅读(5)  评论(0编辑  收藏  举报