ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AtCoder Regular Contest 140

2022-05-16 02:00:52  阅读:192  来源: 互联网

标签:std AtCoder 140 Contest int cin ++ logd Regular


A - Right String

题意

给定一个长度为\(n\)的字符串\(s\),每次可以修改其中一个字符至任意字符,至多使用\(k\)次修改。

记字符串的权重为\(\#\{f(s, i)\}\),\(f(s, i)\)表示将\(s\)循环左移\(i\)次。

其中\(n, k \le 2000\)。

思路

观察可得:答案为字符串的最小整周期。

由于\(n\)比较小,可以直接枚举周期大小,也就是\(n\)的因数,然后再线性检查是否可行。

对于周期\(p\),假设循环节为\(r\),\(r_i\)的选择就是贪心选所有\(s_{i + kp}\)中出现次数最多的。

AC代码
// Problem: A - Right String
// Contest: AtCoder - AtCoder Regular Contest 140
// URL: https://atcoder.jp/contests/arc140/tasks/arc140_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO \
  std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main() {
  CPPIO;
  int T = 1;
  // std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

void solve_case(int Case) {
  int n, k;
  std::string s;
  std::cin >> n >> k;
  std::cin >> s;

  int ans = n;

  auto check = [&](int l) {
    int temp = 0;

    std::vector<std::vector<int>> c(l, std::vector<int>(26, 0));
    for (int i = 0; i < n; ++i) {
      c[i % l][s[i] - 'a']++;
    }

    for (int i = 0; i < l; ++i) {
      int sum = std::accumulate(c[i].begin(), c[i].end(), 0);
      int ma = *std::max_element(c[i].begin(), c[i].end());
      temp += sum - ma;
    }

    if (temp <= k)
      ans = std::min(ans, l);
  };

  for (int l = 1; l * l <= n; ++l) {
    if (n % l == 0) {
      check(l);
      if (l * l != n)
        check(n / l);
    }
  }

  std::cout << ans << "\n";
}

B - Shorten ARC

题意

给定一个长度为\(n\),只包含A,RC的字符串,奇数次操作的时候可以将一个等于ARC的子串替换成R,偶数次操作的时候可以将一个ARC替换成AC

问最大操作次数。

其中\(n \le 2 \times 10^5\)。

思路

形如A...ARC...C这种的子串可以操作1次或者多次,把所有这种子串处理出来,将对应操作次数记录下来。

奇数次操作相当于减1,偶数次操作相当于删除元素。减1贪心用在大的元素上,删除贪心用在小的元素上,用一个std::multiset维护一下就可以了。

AC代码
// Problem: B - Shorten ARC
// Contest: AtCoder - AtCoder Regular Contest 140
// URL: https://atcoder.jp/contests/arc140/tasks/arc140_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO \
  std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main() {
  CPPIO;
  int T = 1;
  // std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

void solve_case(int Case) {
  int n;
  std::cin >> n;

  std::string s;
  std::cin >> s;

  std::vector<int> a;

  for (int i = 0; i < n; ++i) {
    if (s[i] != 'R')
      continue;

    int p, l = 0, r = 0;

    p = i - 1;
    while (p >= 0 && s[p] == 'A') {
      ++l;
      --p;
    }

    p = i + 1;
    while (p < n && s[p] == 'C') {
      ++r;
      ++p;
    }

    int c = std::min(l, r);
    if (c > 0)
      a.push_back(c);
  }

  if (a.empty()) {
    std::cout << "0\n";
    return;
  }

  int l = 1, r = std::accumulate(a.begin(), a.end(), 0), mid, ans = 0;
  while (l <= r) {
    mid = (l + r) >> 1;
    logd(l, r);

    bool can = true;

    std::multiset<int> st;
    st.clear();
    for (int i = 0; i < a.size(); ++i) {
      st.insert(a[i]);
    }

    logd(st);
    for (int i = 1; i <= mid; ++i) {
      if (st.empty()) {
        can = false;
        break;
      }

      if (i & 1) {
        auto it = --st.end();
        int c = *it;
        st.erase(it);
        --c;
        if (c > 0) {
          st.insert(c);
        }
      } else {
        auto it = st.begin();
        st.erase(it);
      }
      logd(i, st);
    }

    if (can)
      l = mid + 1, ans = mid;
    else
      r = mid - 1;
  }

  std::cout << ans << "\n";
}

C - ABS Permutation (LIS ver.)

题意

要求构造一个\((1, \dots, n)\)的排列\(p\),使得\(p_1 = x\)且\(a_i = |p_i - p_{i - 1}|\)的LIS最长。

其中\(n \le 2 \times 10^5\)。

思路

大概就是构造出一个形如\(x, x+1, x-1, x+2, x-2, \dots\)或者\(x, x-1, x+1, x-2, x+2, \dots\)这样的排列。

如果\(n\)为奇数,如果\(x = \lfloor \frac{n}{2} \rfloor + 1\),那么刚好能构造出LIS长度为\(n - 1\)的;否则只能构造出LIS长度为\(n - 2\)的,构造方法见后文。

如果\(n\)为偶数,如果\(x = \frac{n}{2}\)或者\(x =\frac{n}{2} + 1\),那么就能构造出LIS长度为\(n - 1\)的,这里要注意方向的选择;否则只能构造出长度为\(n - 2\)的,构造方法同上。

构造方法:将除了\(x\)之外的其他元素分为两组\(L\)和\(R\),然后两个数组大小向等或者\(L\)比\(R\)多一个元素,且\(L_1 < L_2 < \dots < L_n < R_1 < R_2 < \dots < R_m\),然后\(x, L_n, R_1, L_{n - 1}, R_2, \dots, L_1\)可以满足\(a\)的LIS长度为\(n - 2\)。

AC代码
// Problem: C - ABS Permutation (LIS ver.)
// Contest: AtCoder - AtCoder Regular Contest 140
// URL: https://atcoder.jp/contests/arc140/tasks/arc140_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO \
  std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main() {
  CPPIO;
  int T = 1;
  // std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

void solve_case(int Case) {
  int n, x;
  std::cin >> n >> x;

  std::vector<int> p(n + 1);
  p[1] = x;

  if (n % 2 == 1 && x == n / 2 + 1) {
    for (int i = 2; i <= n; ++i) {
      if (i & 1)
        p[i] = p[i - 1] + (i - 1);
      else
        p[i] = p[i - 1] - (i - 1);
    }
  } else if (n % 2 == 0 && x == n / 2) {
    for (int i = 2; i <= n; ++i) {
      if (i & 1)
        p[i] = p[i - 1] - (i - 1);
      else
        p[i] = p[i - 1] + (i - 1);
    }
  } else if (n % 2 == 0 && x == n / 2 + 1) {
    for (int i = 2; i <= n; ++i) {
      if (i & 1)
        p[i] = p[i - 1] + (i - 1);
      else
        p[i] = p[i - 1] - (i - 1);
    }
  } else {
    std::vector<int> l, r;
    for (int i = 1; i <= n; ++i) {
      if (i == x)
        continue;
      if (l.size() < n / 2)
        l.push_back(i);
      else
        r.push_back(i);
    }
    logd(l, r);
    for (int i = 2, j = l.size() - 1; j >= 0; --j, i += 2) {
      logd(i, j);
      p[i] = l[j];
    }
    for (int i = 3, j = 0; j < r.size(); ++j, i += 2) {
      logd(i, j);
      p[i] = r[j];
    }
  }

  for (int i = 1; i <= n; ++i)
    std::cout << p[i] << " \n"[i == n];

  logd(p);
  for (int i = 1; i <= n; ++i)
    assert(1 <= p[i] && p[i] <= n);
}

D - One to One

题意

给一个长度为\(n\)的数组\(a_i\),\(a_i \ne -1\)表示\(i\)和\(a_i\)之间有一条边,\(a_i = -1\)表示\(a_i\)的可能在\([1, n]\)中任取。

\(f(a)\)表示\(a\)对应的图中连通快的数目。

问所有可能情况中\(f(a)\)的和。

其中\(n \le 2000\)。

思路

建出来的图中,一个连通块对应一个环,然后可以从数连通块转化为数环。

首先是\(a_i \ne -1\)的边组成的环,假设共有\(C\)个,且有\(D\)个\(i\)使得\(a_i = -1\),则这部分的贡献为\(C \times n^D\)。

此时,除了环之外其余连通块都是树,假设有\(K\)棵树,第\(i\)棵树的大小为\(B_i\)。考虑选择其中\(k\)个棵树链接起来组成一个环,假设选取了点\(x_i, 1 \le i \le k\),则这个环的种类有\((k - 1)!\prod_{i = 1}^{k} B_{x_i}\)。假设前\(i\)个点,大小为\(j\)的环共有\(dp_{i, j}\)类,则\(dp_{i, j} = dp_{i - 1, j} + dp_{i - 1, j - 1} \times B_i\)。

然后考虑大小为\(k\)的环对答案的贡献,其值为\(dp_{K, k} \times (k - 1)! \times n^{K - k}\)。

然后就没了。

AC代码
// Problem: D - One to One
// Contest: AtCoder - AtCoder Regular Contest 140
// URL: https://atcoder.jp/contests/arc140/tasks/arc140_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO \
  std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#endif

using i64 = int64_t;
using u64 = uint64_t;

void solve_case(int Case);

int main() {
  CPPIO;
  int T = 1;
  // std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    solve_case(t);
  }
  return 0;
}

struct DSU {
  int n;
  std::vector<int> f, tag, sz;

  DSU(int _n) : n(_n), f(n), tag(n), sz(n) {
    for (int i = 0; i < n; ++i) {
      f[i] = i;
      tag[i] = 0;
      sz[i] = 1;
    }
  }

  int leader(int x) {
    if (f[x] == x)
      return x;
    f[x] = leader(f[x]);
    return f[x];
  }

  bool same(int x, int y) { return leader(x) == leader(y); }

  void merge(int x, int y) {
    x = leader(x);
    y = leader(y);
    if (x == y)
      return;
    f[x] = y;
    sz[y] += sz[x];
  }

  void set(int x) { tag[x] = 1; }
};

const int mod = 998244353;

void solve_case(int Case) {
  int n;
  std::cin >> n;

  std::vector<int> fact(n + 1);
  fact[0] = 1;
  for (int i = 1; i <= n; ++i)
    fact[i] = i64(1) * fact[i - 1] * i % mod;
  std::vector<int> power(n + 1);
  power[0] = 1;
  for (int i = 1; i <= n; ++i)
    power[i] = i64(1) * power[i - 1] * n % mod;

  std::vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    std::cin >> a[i];
    if (a[i] != -1)
      --a[i];
  }

  DSU dsu(n);
  for (int i = 0; i < n; ++i) {
    if (a[i] != -1) {
      if (dsu.same(i, a[i]))
        dsu.set(dsu.leader(i));
      else
        dsu.merge(i, a[i]);
    }
  }

  int C = 0;
  std::vector<int> B(1);
  for (int i = 0; i < n; ++i) {
    if (i != dsu.f[i])
      continue;
    if (dsu.tag[i]) {
      ++C;
      continue;
    }
    B.push_back(dsu.sz[i]);
  }
  logd(B);

  int D = 0;
  for (int i = 0; i < n; ++i) {
    if (a[i] == -1) {
      ++D;
    }
  }
  // cycle constructed by fixed edges
  int fixed = i64(1) * power[D] * C % mod;

  // cycle constructed by mutable edges
  int k = B.size() - 1;
  std::vector<std::vector<int> > dp(k + 1, std::vector<int>(k + 1, 0));
  for (int i = 0; i <= k; ++i)
    dp[i][0] = 1;
  for (int i = 1; i <= k; ++i) {
    for (int j = 0; j <= i; ++j) {
      dp[i][j] = (dp[i - 1][j] + i64(1) * dp[i - 1][j - 1] * B[i] % mod) % mod;
    }
  }
  int dynamic = 0;
  for (int i = 1; i <= k; ++i) {
    dynamic =
        (dynamic + i64(1) * fact[i - 1] * power[k - i] % mod * dp[k][i] % mod) %
        mod;
  }
  int ans = (fixed + dynamic) % mod;
  std::cout << ans << "\n";
}

标签:std,AtCoder,140,Contest,int,cin,++,logd,Regular
来源: https://www.cnblogs.com/zengzk/p/16275498.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有