【Atcoder】AGC024 C-F简要题解

C.Sequence Growing Easy

a n s = ∑ i = 2 , a i > 0 n ( [ a i = a i − 1 + 1 ] + [ a i ≠ a i − 1 + 1 ] a i ) ans =\sum\limits_{i=2,a_i>0}^n([a_i=a_{i-1}+1]+[a_i\neq a_{i-1}+1]a_i) ans=i=2,ai>0n([ai=ai1+1]+[ai̸=ai1+1]ai)


*D.Isomorphism Freak

( u , v ) (u,v) (u,v)同色的条件:找到 ( u , v ) (u,v) (u,v)路径上的中点(一条边/一个点),中点的所有子树同构的,且染色种类数为 m a x d e p maxdep maxdep,所以找到树的直径 D D D,第一问答案即 ⌊ D 2 ⌋ \lfloor\frac{D}{2}\rfloor 2D

  • D D D为奇数,重心为一条边 ( u , v ) (u,v) (u,v),将 ( u , v ) (u,v) (u,v)作为第一层,每层填满,第二问的代价是唯一的。
  • 否则 D D D为偶数,重心为一个点 u u u,可以将 u u u作为第一层求出代价,也可以将任意与 u u u相连的点 v v v u u u一起构成第一层求出代价(使得直径加一,但第一问答案不变),所有情况取 min ⁡ \min min即可。

E.Sequence Growing Hard

如果新增的位置值与原来这个位置的值相等,那么可以认为填的是后面一个位置而不是这个位置。
所以假设填的数是 x x x,要么填在末位,要么它后一个位置的数严格 < x <x <x

在序列末端添一个 0 0 0,每次在一个位置填数并向它后一个位置连边,那么这就是一个树,满足以下条件:

  • t i , w i t_i,w_i ti,wi分别表示点 i i i的添加时间和值。
  • t i t_i ti互不相同, w i ∈ [ 0 , K ] w_i\in [0,K] wi[0,K]
  • t r o o t = 0 , w r o o t = 0 t_{root}=0,w_{root}=0 troot=0,wroot=0
  • t i > t f a i , w i > w f a i t_i>t_{fa_i},w_i>w_{fa_i} ti>tfai,wi>wfai

d p [ i ] [ j ] dp[i][j] dp[i][j]表示 i i i个点, w r o o t = j w_{root}=j wroot=j的方案数,枚举 t t t最小的儿子转移:
d p [ i ] [ j ] = ∑ k = 1 i − 1 ( i − 2 k − 1 ) d p [ i − k ] [ j ] ∑ d = j + 1 K d p [ k ] [ d ] dp[i][j]=\sum\limits_{k=1}^{i-1}\binom{i-2}{k-1}dp[i-k][j]\sum\limits_{d=j+1}^Kdp[k][d] dp[i][j]=k=1i1(k1i2)dp[ik][j]d=j+1Kdp[k][d]

前缀和优化后复杂度 O ( n 2 K ) O(n^2 K) O(n2K)


*F.Simple Subsequence Problem

构造序列自动机,如:
110[00011001]可以转移到1100[0011001],1101[1001]
其中 s [ t ] s[t] s[t]表示已经选了 s s s,要在 t t t中选一个子序列拼上。
构图得到 D A G DAG DAG,直接DP(逐次求出长度为 0 − n 0-n 0n的子序列的方案数,每次只向后转移一步0/1),复杂度 O ( 2 n n ) O(2^nn) O(2nn)

code from wxh010910

#include 

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 1048580;
const int M = 25;

int n, m, len, ans, f[M][N], g[M][N];
char s[N];

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 0; i <= n; ++i) {
    scanf("%s", s);
    for (int j = 0; j < 1 << i; ++j) {
      if (s[j] == '1') {
        f[i][j] = 1;
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 0; j < 1 << i; ++j) {
      int b = j >> (i - 1) & 1, r = 0;
      for (; r < i && (j >> i - r - 1 & 1) == b; ++r);
      g[i][j] = r == i ? -1 : r;
    }
  }
  for (int i = 0; i <= n; ++i) {
    for (int j = 1; i + j <= n; ++j) {
      for (int k = 0; k < 1 << i + j; ++k) {
        f[i][k >> j] += f[i + j][k];
        int t = g[j][k & (1 << j) - 1];
        if (~t) {
          f[i + j - t][(k >> j << j - t) | (k & (1 << j - t) - 1)] += f[i + j][k];
        }
      }
    }
    for (int j = (1 << i) - 1; ~j; --j) {
      if (f[i][j] >= m) {
        len = i, ans = j;
      }
    }
  }
  for (int i = len - 1; ~i; --i) {
    putchar((ans >> i & 1) + '0');
  }
  putchar(10);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

你可能感兴趣的:(妙,树形DP,贪心,构造,atcoder)