Cattle passenger 17439: Endless Pallet

Topic Portal

Algorithm: min-max inclusion and exclusion, tree backpack, NTT.

Description of the meaning of problems

There are a \ (n \) tree points. All start points are white, each operation will randomly select \ (\ frac {n \ times (n + 1)} {2} \) of paths a, all points on the path to black. All the expected number of points are seeking operation is blacked out.

\ (the n-\ Le 50 \) . Multiple sets of data. For \ (998, 244, 353 \) modulo.

answer

Routine manner, we use the min-max inclusion and exclusion.
\ [\ Begin {aligned} E (\ max (U)) & = \ sum _ {\ phi \ neq S \ subset U} (-1) ^ {\ lvert S \ rvert - 1} E (\ min (S) ) \\ & = \ sum _ { \ phi \ neq S \ subset U} (-1) ^ {\ lvert S \ rvert - 1} \ frac {1} {P ( route through \ S \ point inside)} \ \ & = \ sum _ {\ phi \ neq S \ subset U} (-1) ^ {\ lvert S \ rvert - 1} \ frac {1} {1 - P ( the path without passing through the point \ S \ in)} \ end {aligned} \]
If we draw out the tree, and \ (S \) the tags in, can be found, the points of the original tree into a plurality of blocks of communication, and communication with the interior of each block may be chosen arbitrarily path, to ensure that the path does not pass through \ (S \) points therein. Once the communication path across the block, then it must go through \ (S \) points therein.

Referred to would be divided into \ (X \) interconnecting blocks \ (T_l, T_2, \ cdots, T_x \) , without passing \ (S \) path number
\ [\ sum_ {i = 1 } ^ {x} \ frac {\ lvert T_i \ rvert
\ times \ left (\ lvert T_i \ rvert + 1 \ right)} {2} \] then the probability
\ [\ frac {\ sum_ { i = 1} ^ {x} \ lvert t_i \ rvert \ times \ left (
\ lvert t_i \ rvert + 1 \ right)} {n \ times (n + 1)} \] continue to simplify the original formula to give
\ [\ Begin {aligned} E (\ max (U)) & = \ sum _ {\ phi \ neq S \ subset U} (-1) ^ {\ lvert S \ rvert - 1} \ frac {1} {1 - \ dfrac {\ sum_ {i = 1} ^ {x} \ lvert T_i \ rvert \ times \ left (\ lvert T_i \ rvert + 1 \ right)} {n \ times (n + 1)}} \\ & = \ sum _ {\ phi \ neq S \ subset U} (-1) ^ {\ lvert S \ rvert - 1} \ frac {n \ times (n + 1)} {n \ times (n + 1) - \ sum_ {i = 1} ^ { x} \ lvert T_i \ rvert \ times \ left (\ lvert T_i \ rvert + 1 \ right)} \\ & = \ frac {n \ times (n + 1)} {2} \ sum _ {\ phi \ neq S \ subset U} (-1) ^ {\ lvert S \ rvert - 1} \ frac {1} {\ dfrac {n \ times (n + 1)} {2} - \ sum_ {i = 1} ^ {x
} \ dfrac {\ lvert T_i \ rvert \ times \ left (\ lvert T_i \ rvert + 1 \ right)} {2}} \ end {aligned} \] for the final case, one division contribution scheme to bring answers only \ ((- 1) ^ { | S | - 1} \) and \ (\ sum_ {i = 1 } ^ x \ dfrac {\ lvert T_i \ rvert \ times \ left ( \ lvert T_i \ rvert + 1 \ right)} {2} \)Two. To gain this information, we are only interested in the number of points selected odd, even, in the embodiment, the number of programs \ (\ sum_ {i = 1 } ^ x \ dfrac {\ lvert T_i \ rvert \ times \ left ( \ lvert T_i \ rvert + 1 \ right)} {2} \) for my enum constant \ (K \) .

Consider the design of a dynamic programming to solve this problem. We first select \ (1 \) dots as the root of the whole tree, the tree to become a rooted tree.

Note \ (f [i] [odd ] [j] [k] \) represents only considered to \ (I \) subtree rooted, selected from the odd / even number of points, comprising \ (I \) communicates block size \ (J \) , \ (\ sum_ {I =. 1} ^ X \ dfrac {\ lvert T_i \ rvert \ Times \ left (\ lvert T_i \ rvert +. 1 \ right)} {2} \) ( free \ (I \) where the value of the communication block) \ (K \) number scheme. Wherein \ (j = 0 \) represents \ (I \) dot block is not communicating (i.e., focused at the selected point).

Further, we denote an array \ (g [i] [odd ] [k] \) represented by \ (I \) is the root of the subtree is selected from the odd / even dot, \ (\ sum_ {I =. 1} X ^ \ dfrac {\ lvert T_i \ rvert \ Times \ left (\ lvert T_i \ rvert +. 1 \ right)} {2} \) (containing \ (I \) is located in communication block) \ (K \) the number of programs. Clearly
\ [g [i] [odd ] [k '] = \ sum_ {j = 0} ^ n \ sum_ {k = 0} ^ {\ frac {n \ times (n + 1)} {2}} \ left [\ frac {j \ times (j + 1)} {2} + k == k '\ right] f [i] [odd] [j] [k] \]

Transfer backpack similar to the tree. The combined \ (I \) and a son \ (V \) , the metastasis of formula:
\ [F [I] [ODD] [J] [K] = \ left \ {\ the begin {the aligned} & \ sum_ {ODD '\ in \ {0, 1 \}} \ sum_ {k' = 0} ^ {k} f [i] [odd] [j] [k '] \ cdot g [v] [odd \ oplus odd'] [k - k '] \ quad & j = 0 \\ & \ sum_ {odd' \ in \ {0, 1 \}} \ sum_ {j '= 1} ^ {j} \ sum_ {k' = 0} ^ {k} f [i] [odd] [j] [k] \ cdot f [v] [odd \ oplus odd '] [j - j'] [k - k '] \ quad & j \ neq 0 \ end {aligned} \ right. \
] transfer complexity violence \ (\ mathcal {O} ( n ^ 7) \) and unacceptable.

We note that \ (j \) the size of a dimension that does not exceed \ (i \) of the sub-tree size, this is the classic form of the tree backpack. Thus a less complexity \ (n-\) , becomes \ (\ mathcal {O} (n-^. 6) \) .

Continue to observe, it was found \ (K \) transfer is a one-dimensional convolution form, NTT may be used for optimization. In other words, in addition to the \ (f [i] \) to \ (g [i] \) where the calculated contribution, if we take as the last dimension of a state \ (\ frac {n \ times (n + 1)} {2} \) polynomial of degree, then all of this can be viewed as a polynomial computation polynomial multiplication and addition. So we can just represent a point value at the beginning of Act represents \ (f \) and \ (g \) values only in \ (f \) to \ (g \) when the count contributions, we conduct a INTT , the value represents a reduction back to point coefficient representation, to give \ (G \) after, and again can be reduced to the point value representation.

So the original \ (\ mathcal {O} ( n ^ 2) \) transfer is optimized to \ (\ mathcal {O} (\ log n-) \) . After this overall complexity becomes \ (\ mathcal {O} (n-^. 4 \ log n-) \) .

When the test data of each program run I \ (0.5 \ text {S} \) , the number of data sets that question \ (T = 15 \) after the card I was constant. At present only the former had \ (9 \) points, the last \ (3 \) points are still struggling in the regular card.

#include <algorithm>
#include <cstdio>
#include <cstring>

const int MaxN = 50 + 5;
const int MaxV = 4096 + 5;
const int Mod = 998244353, Prt = 3;

struct Graph {
  int cnte;
  int Head[MaxN], To[MaxN * 2], Next[MaxN * 2];

  inline void clear() {
    cnte = 0;
    memset(Head, 0, sizeof Head);
    memset(To, 0, sizeof To);
    memset(Next, 0, sizeof Next);
  }

  inline void addEdge(int from, int to) {
    cnte++; To[cnte] = to;
    Next[cnte] = Head[from]; Head[from] = cnte;
  }
};

int Te, N;
int Fa[MaxN], Siz[MaxN];
int F[MaxN][2][MaxN][MaxV], G[MaxN][2][MaxV];
int Rev[MaxV][MaxV], W[2][MaxV], Inv[MaxV];
Graph Gr;

inline int add(int x, int y) { return (x += y) >= Mod ? x - Mod : x; }
inline int sub(int x, int y) { return (x -= y) < 0 ? x + Mod : x; }
inline int mul(int x, int y) { return 1LL * x * y % Mod; }
inline int pw(int x, int y) { int z = 1; for (; y; y >>= 1, x = mul(x, x)) if (y & 1) z = mul(z, x); return z; }
inline int inv(int x) { return pw(x, Mod - 2); }
inline int sep(int x, int y) { return mul(x, inv(y)); }
inline void inc(int &x, int y = 1) { x = add(x, y); }
inline void dec(int &x, int y = 1) { x = sub(x, y); }

void init() {
  scanf("%d", &N);
  for (int i = 1; i < N; ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    Gr.addEdge(u, v);
    Gr.addEdge(v, u);
  }
}

void dfs1(int u) {
  Siz[u] = 1;
  for (int i = Gr.Head[u]; i; i = Gr.Next[i]) {
    int v = Gr.To[i];
    if (v == Fa[u]) continue;
    Fa[v] = u;
    dfs1(v);
    Siz[u] += Siz[v];
  }
}

inline void ntt(int *a, int n, int f) {
  for (int i = 1; i < n; ++i)
    if (i < Rev[n][i]) std::swap(a[i], a[Rev[n][i]]);
  for (int i = 1; i < n; i <<= 1) {
    int w = W[f][i];
    for (int j = 0; j < n; j += (i << 1)) {
      int x = 1;
      for (int k = 0; k < i; ++k, x = mul(x, w)) {
        int lson = a[j + k], rson = a[i + j + k];
        a[j + k] = add(lson, mul(rson, x));
        a[i + j + k] = sub(lson, mul(rson, x));
      }
    }
  }
  if (f == 1)
    for (int i = 0; i < n; ++i) a[i] = mul(a[i], Inv[n]);
}

inline int getPow2(int n) {
  int v = 1;
  while (v < n) v <<= 1;
  return v;
}

inline void calcG(int u) {
  for (int odd = 0; odd <= 1; ++odd) {
    for (int j = 0; j <= N; ++j)
      for (int k = 0; k <= N * (N + 1) / 2; ++k) {
        int newK = j * (j + 1) / 2 + k;
        if (newK > N * (N + 1) / 2) break;
        inc(G[u][odd][newK], F[u][odd][j][k]);
      }
  }
}

void dfs2(int u) {
  F[u][1][0][0] = F[u][0][1][0] = 1;
  int sz = 1;
  for (int i = Gr.Head[u]; i; i = Gr.Next[i]) {
    int v = Gr.To[i];
    if (v == Fa[u]) continue;
    dfs2(v);
    sz += Siz[v];
    static int f[2][MaxN][MaxV];
    int len = getPow2(Siz[u] * (Siz[u] + 1));
    for (int odd = 0; odd <= 1; ++odd)
      for (int j = 0; j <= sz; ++j)
        for (int k = 0; k < len; ++k)
          f[odd][j][k] = 0;
    for (int odd = 0; odd <= 1; ++odd) {
      ntt(G[v][odd], len, 0);
      for (int j = 0; j <= sz - Siz[v]; ++j) ntt(F[u][odd][j], len, 0);
      for (int j = 0; j <= Siz[v]; ++j) ntt(F[v][odd][j], len, 0);
    }

    for (int odd = 0; odd <= 1; ++odd) {
      for (int j = 0; j <= sz; ++j) {
        for (int odd2 = 0; odd2 <= 1; ++odd2) {
          if (j == 0) {
            for (int k = 0; k < len; ++k)
              inc(f[odd][j][k], mul(F[u][odd ^ odd2][j][k], G[v][odd2][k]));
          } else {
            for (int j2 = std::max(0, j - sz + Siz[v]); j2 <= Siz[v] && j2 < j; ++j2) {
              for (int k = 0; k < len; ++k)
                inc(f[odd][j][k], mul(F[u][odd ^ odd2][j - j2][k], F[v][odd2][j2][k]));
            }
          }
        }
      }
    }

    for (int odd = 0; odd <= 1; ++odd) {
      ntt(G[v][odd], len, 1);
      for (int j = 0; j <= sz - Siz[v]; ++j) ntt(F[u][odd][j], len, 1);
      for (int j = 0; j <= Siz[v]; ++j) ntt(F[v][odd][j], len, 1);
      for (int j = 0; j <= sz; ++j) ntt(f[odd][j], len, 1);
    }
    for (int odd = 0; odd <= 1; ++odd)
      for (int j = 0; j <= sz; ++j)
        for (int k = 0; k <= sz * (sz + 1) / 2; ++k)
          F[u][odd][j][k] = f[odd][j][k];
  }
  calcG(u);
}

void solve() {
  dfs1(1);
  dfs2(1);
  int ans = 0;
  for (int odd = 0; odd <= 1; ++odd)
    for (int k = 0; k < N * (N + 1) / 2; ++k) {
      if (odd == 1) inc(ans, mul(G[1][odd][k], inv(N * (N + 1) / 2 - k)));
      else dec(ans, mul(G[1][odd][k], inv(N * (N + 1) / 2 - k)));
    }
  ans = mul(ans, N * (N + 1) / 2);
  printf("%d\n", ans);
}

void clear() {
  memset(Fa, 0, sizeof Fa);
  memset(Siz, 0, sizeof Siz);
  memset(F, 0, sizeof F);
  memset(G, 0, sizeof G);
  Gr.clear();
}

int main() {
  for (int i = 1; i <= 4096; i <<= 1) {
    Rev[i][0] = 0;
    for (int j = 1; j < i; ++j) {
      Rev[i][j] = (Rev[i][j >> 1]) >> 1;
      if (j & 1) Rev[i][j] |= (i >> 1);
    }
    Inv[i] = inv(i);
  }
  for (int f = 0; f <= 1; ++f)
    for (int i = 1; i < 4096; i <<= 1)
      W[f][i] = pw(pw(Prt, f == 0 ? 1 : Mod - 2), (Mod - 1) / (i << 1));
  scanf("%d", &Te);
  for (int t = 1; t <= Te; ++t) {
    init();
    printf("Case #%d: ", t);
    solve();
    clear();
  }
  return 0;
}

Guess you like

Origin www.cnblogs.com/tweetuzki/p/11959888.html