SVUCPC

GYM 105264 C

题目描述

给定一个长度为 \(N\) 的数组 \(A\),每次你可以令 \(A_i \leftarrow A_i+1\)\(A_i-1\)。求进行至多 \(k\) 次操作后 \(A\) 中最少不同元素数量。

思路

首先对 \(A\) 进行排序。

\(dp_{i,j}\) 表示考虑前 \(i\) 个数,有 \(j\) 个不同的值时最多还能剩余几次操作。

很明显有 \(dp_{i,j}=\max \limits_{1\le l\le x\le i} \{dp_{l-1,j-1}+sum_i - sum_{x}-(i-x)\cdot A_x + (x - l)\cdot A_x - sum_{x-1}+sum_l\}\)

这个式子中似乎只能优化 \(x\),所以我们考虑怎么优化。

这里的 \(x\) 实际上就是在枚举变成哪个值,假设一开始我们不用下标而用值来表示。每次令 \(x\leftarrow x+1\),这样做会使答案 \(+\le x的个数-> x的个数\),一开始这个增量是负的,逐渐变大。而当增量 \(=0\) 时也就是最小值。

而哪个地方 \(=0\) 呢?此时 \(\le x的个数=> x的个数\),也就是在 \(\lceil \frac{l+i}{2} \rceil\) 处。

空间复杂度 \(O(N^2)\),时间复杂度 \(O(N^3)\)

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXN = 301;

int T, n, a[MAXN], ans;
ll k, sum[MAXN], dp[MAXN][MAXN];

void Solve() {
  cin >> n >> k;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
  }
  sort(a + 1, a + n + 1);
  for(int i = 1; i <= n; ++i) {
    sum[i] = sum[i - 1] + a[i];
  }
  for(int i = 0; i <= n; ++i) {
    for(int j = 0; j <= n; ++j) {
      dp[i][j] = -1;
    }
  }
  dp[0][0] = k;
  for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= n; ++j) {
      for(int l = 1; l <= i; ++l) {
        dp[i][j] = max(dp[i][j], dp[l - 1][j - 1] + sum[(l + i + 1) / 2] + 1ll * a[(l + i + 1) / 2] * (i - (l + i + 1) / 2) - 1ll * a[(l + i + 1) / 2] * ((l + i + 1) / 2 - l) + sum[(l + i + 1) / 2 - 1] - sum[l - 1] - sum[i]);
      }
    }
  }
  for(int i = 1; i <= n; ++i) {
    if(dp[n][i] >= 0) {
      cout << i << "\n";
      return;
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> T; T--; Solve()) {
  }
  return 0;
}

GYM 105264 E

题目描述

给定一个 \(N\) 个点的树,你要从中选出一个大小为 \(k\) 的子树出来,求这个子树的最小直径。

思路

由于此题允许 \(O(N^2)\) 的时间复杂度,所以考虑枚举子树的中心。

接着以该中心为根向下搜出深度为 \(i\) 的结点数 \(cnt_i\),接着枚举直径长度除 \(2\)。由于这里直径可能长度为偶数,则此时中点在一条边上。所以我们把每条边也看作一个点(但不统计在 \(cnt\) 中)。找到第一个 \(\sum \limits_{i=0}^x cnt_i \ge k\)\(x\),并统计答案即可。

空间复杂度 \(O(N)\),时间复杂度 \(O(N^2)\)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 2001;

int n, k, dep[MAXN], cnt[MAXN], ans;
vector<int> e[MAXN];

void dfs(int u, int fa) {
  dep[u] = dep[fa] + 1;
  cnt[dep[u]] += (u <= n);
  for(int v : e[u]) {
    if(v != fa) {
      dfs(v, u);
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> k;
  for(int i = 1, u, v; i < n; ++i) {
    cin >> u >> v;
    e[u].push_back(n + i);
    e[n + i].push_back(v);
    e[v].push_back(n + i);
    e[n + i].push_back(u);
  }
  ans = 2 * n;
  for(int i = 1; i < 2 * n; ++i) {
    for(int j = 1; j <= 2 * n; ++j) {
      dep[j] = cnt[j] = 0;
    }
    dfs(i, 0);
    int res = 0;
    for(int j = 1; j <= 2 * n; ++j) {
      res += cnt[j];
      if(res >= k) {
        ans = min(ans, j);
        break;
      }
    }
  }
  cout << ans;
  return 0;
}
posted @ 2024-09-26 12:04  Yaosicheng124  阅读(10)  评论(0编辑  收藏  举报