首页 > 其他分享 >Public NOIP Round #7 T3 黑白棋子 题解

Public NOIP Round #7 T3 黑白棋子 题解

时间:2024-10-22 16:42:58浏览次数:7  
标签:std kMod 连通 NOIP int 题解 T3 棋子 mx

Description

有一棵 \(n\) 个点的树,顶点的编号为 \(1\) 到 \(n\)。

对于树中的每个顶点,可能存在一个白色的棋子、一个黑色的棋子,或者没有棋子。树上正好有 \(w\) 个白色棋子和 \(b\) 个黑色棋子。另外,对于每一对具有相同颜色棋子的顶点,存在一条路径,路径上的每个顶点都包含相同颜色的棋子(即每种颜色的棋子形成一个连通块)。

你可以进行任意次以下操作:

  • 选择一个带有棋子的顶点 \(u\)。
  • 选择一条路径 \(p_1, p_2, \dots, p_k\),使得 \(p_1 = u\),且所有顶点 \(p_1, p_2, \dots, p_{k-1}\) 都包含相同颜色的棋子,且 \(p_k\) 上没有棋子
  • 将 \(p_1\) 上的棋子移动到 \(p_k\)。此时 \(p_1\) 上没有棋子,\(p_k\) 上有一个棋子。

在每一步操作后,每种颜色的棋子仍然形成一个连通块。
对于两个初始的棋子状态 \(S\) 和 \(T\),如果你可以通过上述操作若干次(可以为零次)将 \(S\) 变为 \(T\),那么我们认为 \(S\) 和 \(T\) 是等价的。

定义 \(f(w, b)\) 为在树上有 \(w\) 个白色棋子和 \(b\) 个黑色棋子时,等价类的数量。你需要求出:

\[\left(\sum_{w=1}^{n-1}\sum_{b=1}^{n-w} f(w,b)\cdot w\cdot b\right)\bmod 10^9+7 \]

\(n \ge 2,1\le \sum n\le 2\times 10^5,1\le fa_i<i\)。

link

Solution

考虑怎么对于给定的 \(w,b\) 求出 \(f(w,b)\)。

不妨设 \(w\geq b\),\(mx_i\) 表示把 \(i\) 号点删掉后剩余子树的最大大小。

那么如果 \(w>mx_i\),则所有大小为 \(w\) 的连通块都包含 \(i\)。

容易发现所有的必经点构成一个连通块,把这些必经点去掉后剩余的每个连通块之间都互不连通,所以黑色的连通块一定只与和其属于同一个连通块的黑色连通块等价,于是 \(f(w,b)\) 就等于把必经点删掉后大小不小于 \(b\) 的连通块数。

但是可能不存在必经点,即 \(w\leq\min\left\{mx_i\right\}\)。经过手玩会发现此时的 \(f(w,b)\) 只可能等于 \(1\) 或 \(2\)。

并且 \(f(w,b)=1\) 的条件为存在一个点 \(u\),其存在两个子树的大小 \(\geq w\) 和另一个子树大小 \(\geq b\),这是因为如果存在这样的点 \(u\),移动黑色和白色连通块时可以先将后移动的连通块先寄存在一个不可能被经过的子树,等先移动的连通块动完再动,显然这样一定能构造出一组移动方案。

如果不满足那个条件,感性理解一下,黑色和白色连通块一定存在一个“先后顺序”,并且在移动的过程中这个顺序一定不会变,所以有 \(2\) 种等价类。

对于存在必经点的情况,将重心当作根,直接枚举 \(w\) 并维护删掉必经点后的每个子树的大小。如果不存在必经点,维护出满足 \(f(w,b)=1\) 的最大的 \(b\) 即可。

时间复杂度:\(O(n\log n)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 2e5 + 5, kMod = 1e9 + 7;

int n;
int p[kMaxN], sz[kMaxN], mx[kMaxN], suf[kMaxN], pos[kMaxN];
std::vector<int> G[kMaxN];

constexpr int qpow(int bs, int64_t idx = kMod - 2) {
  int ret = 1;
  for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod)
    if (idx & 1)
      ret = (int64_t)ret * bs % kMod;
  return ret;
}

inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }
inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); }
inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }
inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }

int getsum(int n) {
  return 1ll * n * (n + 1) % kMod * ((kMod + 1) / 2) % kMod;
}
int getsum(int l, int r) {
  if (l > r) return 0;
  else return sub(getsum(r), getsum(l - 1));
}

void dfs(int u, int fa) {
  std::vector<int> vsz;
  sz[u] = 1, mx[u] = 0;
  for (auto v : G[u]) {
    if (v == fa) continue;
    dfs(v, u);
    sz[u] += sz[v], mx[u] = std::max(mx[u], sz[v]);
    vsz.emplace_back(sz[v]);
  }
  mx[u] = std::max(mx[u], n - sz[u]);
  vsz.emplace_back(n - sz[u]);
  std::sort(vsz.begin(), vsz.end(), std::greater<>());
  if (vsz.size() >= 3) {
    suf[vsz[1]] = std::max(suf[vsz[1]], vsz[2]);
  }
}

void dickdreamer() {
  std::cin >> n;
  for (int i = 1; i <= n; ++i) G[i].clear();
  std::fill_n(suf, n + 2, 0);
  for (int i = 2; i <= n; ++i) {
    std::cin >> p[i];
    G[p[i]].emplace_back(i), G[i].emplace_back(p[i]);
  }
  dfs(1, 0);
  std::vector<int> vec;
  for (int i = 1; i <= n; ++i) vec.emplace_back(i);
  std::sort(vec.begin(), vec.end(), [&] (int i, int j) { return mx[i] < mx[j]; });
  for (int i = 0; i < n; ++i) pos[vec[i]] = i;
  dfs(vec[0], 0);
  int ans = 0;
  for (int i = n; i; --i) {
    suf[i] = std::max(suf[i], suf[i + 1]);
    if (i > mx[vec[0]]) continue;
    int val = std::min(suf[i], i);
    if (val < i) {
      inc(ans, 2ll * i % kMod * getsum(1, val) % kMod);
      inc(ans, 4ll * i % kMod * getsum(val + 1, i - 1) % kMod);
      inc(ans, 2ll * i % kMod * i % kMod);
    } else {
      inc(ans, 2ll * i * getsum(1, i - 1) % kMod);
      inc(ans, 1ll * i * i % kMod);
    }
  }
  int now = getsum(n);
  for (int i = mx[vec[0]] + 1, j = 0; i <= n; ++i) {
    for (; j < n && mx[vec[j]] < i; ++j) {
      dec(now, getsum(sz[vec[j]]));
      for (auto v : G[vec[j]])
        if (pos[v] > j)
          inc(now, getsum(sz[v]));
    }
    inc(ans, 2ll * i * now % kMod);
  }
  std::cout << ans << '\n';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:std,kMod,连通,NOIP,int,题解,T3,棋子,mx
From: https://www.cnblogs.com/Scarab/p/18493273

相关文章

  • AT_agc064_c [AGC064C] Erase and Divide Game 题解
    先考虑所有\(l_i=r_i\)时怎么做,可以建出反向Trie树,问题转化为从根开始每次向左子树或右子树走,第一个拿到空子树的人输,直接在Trie上dp即可。考虑从叶子层开始对每一层的点合并两个子树的dp值,发现每一层值相同的连续段是较少的。于是可以维护这些连续段,每次合并要将每个......
  • 洛谷P2596 [ZJOI2006] 书架 题解 splay tree 模板题
    题目链接:https://www.luogu.com.cn/problem/P2596主要涉及的操作就是:找到某一个编号的点(这个操作可以不用splaytree维护)删除某个点将某一个点插入到最前面,最后面,或者某一个位置查询前序遍历为\(k\)的节点编号因为每次删除都会又把这个点加回去,所以可以复用\(n\)个......
  • 多校A层冲刺NOIP2024模拟赛11
    又双叒叕垫底了。rank11,T190,T212,T35,T435。accdoer上rank44,T1100,T20,T35,T435。难度难评,T1签,剩下的不可做?死磕T3了,猜一个结论假一个,打完暴力遗憾离场。好像两个题库都挂了几分,不管了,赛前挂分RP就++。慢报:5k_sync_closer成功地取得了NFLS模拟赛第一名的好成绩。冒泡......
  • [题解]CF825E Minimal Labels
    LPhang为什么是神?思路显然可以想到一个错误的贪心:直接拓扑排序,每一次选择当前可以拓展的点中最小的元素进行编号。由于可能存在一个值较小的元素被藏在一个较大的元素后面,这种贪心就会出问题。出问题的本质原因就是我们希望字典序最小,就得使得越小的位置分配到更小的值。不妨......
  • 历年CSP-J初赛真题解析 | 2017年CSP-J初赛完善程序(27-36)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客(快速幂)请完善下面的程序,该程序使用分治法求x......
  • CF2023D Many Games 题解
    赛时被创四了。思路考虑我们什么时候合并会比原来优。例如,我们现在要合并\(p_1,w_1\)和\(p_2,w_2\),同时保证,\(w_1\gew_2\)。那么有:\[\frac{p_1}{100}\timesw_1\le\frac{p_1}{100}\times\frac{p_2}{100}\times(w_1+w_2)\]\[\frac{p_2}{100}\timesw_2\le\frac{p_1}{......
  • 01 Eclipse使用Maven慢的问题解决
    1.Eclipse使用的是内置的MavenEclipse有可能使用了内置的Maven,而不是独立安装的Maven。如果使用Eclipse内置的Maven,默认的settings.xml可能并未生成。你可以按以下步骤检查或修改Maven设置路径:a.检查Eclipse使用的Maven配置点击Window->Preferences在......
  • 【题解】Solution Set - NOIP2024集训Day58 字符串
    【题解】SolutionSet-NOIP2024集训Day58字符串https://www.becoder.com.cn/contest/5658「CF1466G」SongoftheSirens考虑对于\(s_i\),算钦定必须覆盖到\(t_i\)的匹配个数\(f_i\)。注意到\(s\)每次长度都会\(\times~2\)左右,其长度在\(O(\log|w|)\)的时候就......
  • noi.ac775题解
    Gameb文件OI:gameb时限:1000ms空间:512MiBAlice和Bob正在玩一个游戏。具体来说,这个游戏是这样的,给定一个数列,从Alice开始,两个人轮流操作,每次操作可以从数列的头部或者尾部删去一个数字,当这个数列满足一定条件的时候,最后一次操作的人获胜。如果一开始就满足条......
  • CSP2024 前集训:多校A层冲刺NOIP2024模拟赛10
    前言不想说啥了最简单的一题是紫,去死吧只改了T1、T2,T2原题翻译和赛时题面描述都很唐,赛后断断续续加了好多hack。T1岛屿设\(f_{a,b}\)表示\(a\)条两端同色链,\(b\)条两端异色链时连通块数量的期望。红红蓝蓝相连得到红蓝\(\tof_{a-1,b+1}\)。红红红蓝相连得到红红......