比赛链接:Here

A - Cabbages

B - Bouzu Mekuri

C - Colorful Candies

用map维护连续一段区间的不同元素即可。

  1. int main() {
  2. cin.tie(nullptr)->sync_with_stdio(false);
  3. int n, k; cin >> n >> k;
  4. vector<int>a(n + 1);
  5. map<int, int>mp;
  6. for (int i = 1; i <= n; ++i)cin >> a[i];
  7. for (int i = 1; i <= k; ++i)mp[a[i]]++;
  8. int ans = mp.size();
  9. for (int i = k + 1; i <= n; ++i) {
  10. mp[a[i]]++;
  11. mp[a[i - k]]--;
  12. if (mp[a[i - k]] == 0) mp.erase(a[i - k]);
  13. ans = max(ans, (int)mp.size());
  14. }
  15. cout << ans << "\n";
  16. }

D - National Railway

给一个矩阵,矩阵每一个位置都有值,要求选取两个位置使得: AtCoder Beginner Contest 210 - 图1 两个位置的值之和 AtCoder Beginner Contest 210 - 图2 两个位置的曼哈顿距离 AtCoder Beginner Contest 210 - 图3 系数 AtCoder Beginner Contest 210 - 图4 最小。


思路:显然不能枚举两个位置,考虑DP,

AtCoder Beginner Contest 210 - 图5#card=math&code=f%28i%2C%20j%29&id=VApki) 表示在从 AtCoder Beginner Contest 210 - 图6#card=math&code=%281%2C%201%29&id=ESXV9) 到 AtCoder Beginner Contest 210 - 图7#card=math&code=%28i%2C%20j%29&id=Md0U3) 内的元素到 AtCoder Beginner Contest 210 - 图8#card=math&code=%28i%2C%20j%29&id=Y7bQC)的距离加上值的最小值。这个就很好转移了。需要注意的是选取的两个点不一定是左上,右下的关系,所以需要沿着右上左下再做一次。

  1. const int N = 1e3 + 10;
  2. ll a[N][N];
  3. int main() {
  4. cin.tie(nullptr)->sync_with_stdio(false);
  5. ll H, W, C;
  6. cin >> H >> W >> C;
  7. vector<vector<ll>>dp(H, vector<ll>(W)), a(H, vector<ll>(W));
  8. for (int i = 0; i < H; ++i)for (int j = 0; j < W; ++j)cin >> a[i][j];
  9. ll _ = 2, Mi = 1ll << 60;
  10. while (_--) {
  11. for (int i = 0; i < H; ++i)
  12. for (int j = 0; j < W; ++j) {
  13. ll up = (i - 1 >= 0 ? dp[i - 1][j] : 1ll << 60);
  14. ll left = (j - 1 >= 0 ? dp[i][j - 1] : 1ll << 60);
  15. dp[i][j] = min(a[i][j], min(up, left) + C);
  16. Mi = min(Mi, min(up, left) + C + a[i][j]);
  17. }
  18. reverse(a.begin(), a.end());
  19. }
  20. cout << Mi << "\n";
  21. }

E - Ring MST

AtCoder Beginner Contest 210 - 图9个顶点,AtCoder Beginner Contest 210 - 图10 种能够花费 AtCoder Beginner Contest 210 - 图11 连接顶点i ii和 AtCoder Beginner Contest 210 - 图12 的边,AtCoder Beginner Contest 210 - 图13 可以随便取, 边数无限。问使得图连通最少花费。如果不能连通输出 AtCoder Beginner Contest 210 - 图14

把图连通,花费最小,考虑最小生成树的思想,先选择花费最小的边去连,如果两个顶点在同一集合,就不连。本题 AtCoder Beginner Contest 210 - 图15,不能建边做。但可以用类似的思想,先找出花费最小的边的种类,假设这种边可以连接 AtCoder Beginner Contest 210 - 图16AtCoder Beginner Contest 210 - 图17 , 然后一直使用这种边去连接顶点,最后无法再连的时候所有点就会被分成AtCoder Beginner Contest 210 - 图18#card=math&code=gcd%28n%2C%20a%29&id=R2DJx) 个集合,即连接了 AtCoder Beginner Contest 210 - 图19#card=math&code=n%20-%20gcd%28n%2C%20a%29&id=Vh8wt)条边。继续用花费第二小的边连接顶点,可以发现当不能再连接的时候,所有点被分成AtCoder Beginner Contest 210 - 图20#card=math&code=gcd%28n%2C%20a%2C%20a%5E%7B%27%7D%29&id=sXmQn)个集合,一直这样做,如果AtCoder Beginner Contest 210 - 图21能等于 AtCoder Beginner Contest 210 - 图22 ,就说明已经连通了。

  1. int main() {
  2. cin.tie(nullptr)->sync_with_stdio(false);
  3. int n, m;
  4. cin >> n >> m;
  5. pair<int, int>p[m + 1];
  6. for (int i = 1; i <= m; ++i) cin >> p[i].second >> p[i].first;
  7. sort(p + 1, p + 1 + m);
  8. ll ans = 0;
  9. for (int i = 1; i <= m; ++i) {
  10. int d = __gcd(n, p[i].second);
  11. ans += 1ll * (n - d) * p[i].first;
  12. n = d;
  13. }
  14. cout << (n == 1 ? ans : -1);
  15. }

F - Coprime Solitaire

不会