【Atcoder】AGC024 C-F简要题解

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ https://blog.csdn.net/corsica6/article/details/88835697

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)


*D.Isomorphism Freak

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

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

E.Sequence Growing Hard

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

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

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

d p [ i ] [ j ] dp[i][j] 表示 i i 个点, w r o o t = j w_{root}=j 的方案数,枚举 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]

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


*F.Simple Subsequence Problem

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

code from wxh010910

#include <bits/stdc++.h>

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;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/88835697