[ARC150D] Removing Gacha

由于期望的线性性,并且这个坏点的问题看上去不是很好处理,那么我们不妨想一想每个点会被涂黑多少次。
很显然一个点会被涂黑的次数可以移到链上考虑,并且深度大于这个点的点都不需要考虑。
我们可以看作在涂满之前随便选择,而不去考虑最长的涂黑前缀,为什么呢?

因为我们如果选择了一个最长涂黑前缀上的点,是对答案没有任何影响的,也就是说对于最后一个点来说选择任意选点无所谓,然后根据初中概率学,

随机选择一个点如果不合法就再选择一次等价于不考虑不合法的点进行选择

那么对于一个深度为 d 的点,它被操作的期望步数就是随机涂黑链上全部 d 个点,最终他被涂黑的次数。这是经典问题。涂黑 i 个点之后,选择下一个白点的概率就是 nin 期望步数就是 nni 总期望步数就是 nΣi=1n1i=nHn,每个点等价,那么每个点的操作步数都是 Hn(调和级数)。记 deepth[i] 为深度,本题的答案就是 ΣxHdeepth[x]
代码如下

#include<bits/stdc++.h>
#define RG register
#define LL long long
#define U(x, y, z) for(RG int x = y; x <= z; ++x)
#define D(x, y, z) for(RG int x = y; x >= z; --x)
#define update(x, y) (x = x + y >= mod ? x + y - mod : x + y)
using namespace std;
void read(){}
template<typename _Tp, typename... _Tps>
void read(_Tp &x, _Tps &...Ar) {
	x = 0; char ch = getchar(); bool flg = 0;
	for (; !isdigit(ch); ch = getchar()) flg |= (ch == '-');
	for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
	if (flg) x = -x;
	read(Ar...);	
}
inline char Getchar(){ char ch; for (ch = getchar(); !isalpha(ch); ch = getchar()); return ch;}
template <typename T> inline void write(T n){ char ch[60]; bool f = 1; int cnt = 0; if (n < 0) f = 0, n = -n; do{ch[++cnt] = char(n % 10 + 48); n /= 10; }while(n); if (f == 0) putchar('-'); for (; cnt; cnt--) putchar(ch[cnt]);}
template <typename T> inline void writeln(T n){write(n); putchar('\n');}
template <typename T> inline void writesp(T n){write(n); putchar(' ');}
template <typename T> inline void chkmin(T &x, T y){x = x < y ? x : y;}
template <typename T> inline void chkmax(T &x, T y){x = x > y ? x : y;}
template <typename T> inline T Min(T x, T y){return x < y ? x : y;}
template <typename T> inline T Max(T x, T y){return x > y ? x : y;}
inline void readstr(string &s) { s = ""; static char c = getchar(); while (isspace(c)) c = getchar(); while (!isspace(c)) s = s + c, c = getchar();}
inline void FO(string s){freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout);}

const int N = 2e5 + 10, mod = 998244353;
LL inv[N], H[N];
int n, depth[N];

int main(){
	//FO("");
	read(n);
	inv[1] = 1;
	H[1] = 1;
	U(i, 2, n) {
		inv[i] = inv[mod % i] * (mod - mod / i) % mod;
		H[i] = H[i - 1];
		update(H[i], inv[i]);
	}
	// cerr << inv[10] * 10 % mod << "\n";
	depth[1] = 1;
	LL ans = 1;
	// cout << (1 + H[2] + H[2] + H[3]) % mod << '\n';
	U(i, 2, n) {
		int fa;
		read(fa);
		depth[i] = depth[fa] + 1;
		// cerr << depth[i] << "\n";
		update(ans, H[depth[i]]);
	}
	writeln(ans);
	return 0;
}
posted @   Southern_Way  阅读(45)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示