首页 > 其他分享 >P6049 燔祭 题解

P6049 燔祭 题解

时间:2024-05-28 21:58:04浏览次数:14  
标签:int 题解 P6049 1ll ans include sum mod

题意:

计算满足如下条件的带标号有根树数量:

  • 这棵树一共有 \(n\) 个节点。
  • 每个节点都有一个整数权值,且在区间 \([1,m]\) 内。
  • 每个节点的权值都不大于其父节点的权值。

\(n,m \le 400\)


思路:

好题。

对于这种计数问题,肯定第一眼会想到 \(dp\),我们设 \(f_{n,m}\) 表示 \(n\) 个点的有标号树,根的权值是 \(m\) 的方案数,转移则是:

\[f_{n,m} = \sum_{k=0}^{n-1}\sum_{i_1 + i_2 + \dots + i_k = n - 1}\binom{n-1}{i_1,i_2,\dots,i_k}(\sum_{j=0}^{m}f_{i_1,j})(\sum_{j=0}^{m}f_{i_2,j})\dots(\sum_{j=0}^{m}f_{i_k,j}) \]

然后我们发现这是一个标准的用 EGF 优化的形式,不妨设 \(g_{n,m} = \sum_{j = 0}^m f_{n,j}\),\(F_m(x) = \sum_{n}\frac{f_{n,m}x^n}{n!}\) 和 \(G_m(x) = \sum_{n}\frac{g_{n,m}x^n}{n!}\)。

我们就可以得到这样的转移式:

\[F_m(x) = xe^{G_m(x)} = xe^{G_{m-1}(x) + F_m(x)} \]

回到问题本身,我们发现答案应该是一个关于 \(m\) 的 \(n\) 次多项式,这个可以从上面的 \(dp\) 转移式中看出来,也可以通过发现答案粗略上界是 \((nm)^n\) 看出来。

于是我们只要计算出了 \(f_{n,1} \sim f_{n, n + 1}\) 就可以插值得到 \(f_{n,m}\)。

考虑到多项式 exp 有一种神奇的 \(O(n^2)\) 递推的解法:如果要求 \(B = e^{A}\),两边取导得到:\(B'= BA'\),展开系数得到:

\[(n+1)B_{n+1} = \sum_{i=0}^n(i+1)A_{i+1}B_{n-i} \]

也就是:

\[B_{n} = \frac{1}{n}\sum_{i=1}^{n}iA_{i}B_{n-i} \]

于是我们可以直接这样来求,考虑到 \(F = xe^{F}e^{G}\),展开系数得到:

\[F_{n} = \sum_{i=0}^{n-1}F_iG_{(n-1)-i} \]

于是我们通过逐步递推出 exp 就可以在 \(O(n^3)\) 内解出来。

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 405;
const int mod = 998244353;

int fpow(int a, int b, int p) {
	if (b == 0)
		return 1;
	int ans = fpow(a, b / 2, p);
	ans = 1ll * ans * ans % p;
	if (b % 2 == 1)
		ans = 1ll * a * ans % p;
	return ans;
}
int mmi(int a, int p) {
	return fpow(a, p - 2, p);
}

int fac[N] = {0}, inv[N] = {0}, inv2[N] = {0};

void init(int n) {
	fac[0] = 1;
	for (int i = 1; i <= n; i++)
		fac[i] = 1ll * i * fac[i - 1] % mod;
	inv[n] = mmi(fac[n], mod);
	for (int i = n - 1; i >= 0; i--)
		inv[i] = 1ll * (i + 1) * inv[i + 1] % mod;
	inv2[1] = 1;
	for (int i = 2; i <= n; i++)
		inv2[i] = 1ll * (mod - mod / i) * inv2[mod % i] % mod;
}

int n, m;

int F[N][N] = {{0}}, G[N][N] = {{0}}; 
int f[N][N] = {{0}}, g[N][N] = {{0}};

void upd(int i) {//计算 F[i][1 ... n] 的值 
	//利用 G[i] 来储存 exp G[i - 1]
	g[i][0] = 1;
	for (int j = 1; j <= n; j++) {
		for (int k = 1; k <= j; k++)
			g[i][j] = (g[i][j] + 1ll * k * G[i - 1][k] % mod * g[i][j - k] % mod) % mod;
		g[i][j] = 1ll * g[i][j] * inv2[j] % mod;
	}
	
	//计算 F[i]
	f[i][0] = 1;
	for (int j = 1; j <= n; j++) {
		for (int k = 0; k <= j - 1; k++)
			F[i][j] = (F[i][j] + 1ll * f[i][k] * g[i][(j - 1) - k] % mod) % mod;
		//递推出 f[i][j]
		for (int k = 1; k <= j; k++)
			f[i][j] = (f[i][j] + 1ll * k * F[i][k] % mod * f[i][j - k] % mod) % mod;
		f[i][j] = 1ll * f[i][j] * inv2[j] % mod;
	} 
	//计算 G[i]
	for (int j = 1; j <= n; j++)
		G[i][j] = (G[i - 1][j] + F[i][j]) % mod; 
}

int prx[N] = {0}, suf[N] = {0};
void Lagrange() {
	prx[0] = 1;
	for (int i = 1; i <= n + 1; i++)
		prx[i] = 1ll * prx[i - 1] * (m - i + mod) % mod;
	suf[n + 2] = 1;
	for (int i = n + 1; i >= 1; i--)
		suf[i] = 1ll * suf[i + 1] * (m - i + mod) % mod;
	int ans = 0;
	for (int i = 1; i <= n + 1; i++) 
		if ((n + 1 - i) % 2 == 0)
			ans = (ans + 1ll * G[i][n] * prx[i - 1] % mod * suf[i + 1] % mod * inv[i - 1] % mod * inv[n + 1 - i] % mod) % mod;
		else
			ans = (ans - 1ll * G[i][n] * prx[i - 1] % mod * suf[i + 1] % mod * inv[i - 1] % mod * inv[n + 1 - i] % mod + mod) % mod;
	cout << ans << endl;
}

int main() {
	cin >> n >> m;
	init(n + 1);
	//先递推出 F 和 G
	//初始 i ^ i-1
	for (int i = 1; i <= n; i++)
		F[1][i] = G[1][i] = 1ll * fpow(i, i - 1, mod) * inv[i] % mod;
	for (int i = 2; i <= n + 1; i++) 
		upd(i);
	//求出 G[1, 2, ..., n + 1][n] 然后插值 
	for (int i = 1; i <= n + 1; i++)
		G[i][n] = 1ll * fac[n] * G[i][n] % mod;
	Lagrange();
	return 0;
} 

标签:int,题解,P6049,1ll,ans,include,sum,mod
From: https://www.cnblogs.com/rlc202204/p/18218997

相关文章

  • ICPC2024昆明邀请赛 J The Quest for El Dorado 题解
    QuestionTheQuestforElDorado有一个王国,有\(n\)个城市和\(m\)条双向铁路连接这些城市。第\(i\)条铁路由第\(c_i\)家铁路公司运营,铁路的长度为\(l_i\)。你想要环游这个国家,从城市\(1\)出发。为了你的旅行,你购买了\(k\)张火车票。第\(i\)张火车票用两个整数\(......
  • 题解/算法 {C. Goose Goose Duck}
    题解/算法{C.GooseGooseDuck}@LINK:https://codeforces.com/gym/105184;令A[N]表示这N个人的区间;比如答案是[a,b,c,d]那么他一定满足:A[a].lef<=0<=A[a].rig,A[b].lef<=1<=A[b].rig,A[c].lef<=2<=A[c].rig,…贪心;对于最开头的人来说,令集合S:......
  • 题解/算法 {J - Iris‘ Food}
    题解/算法{J-Iris’Food}@LINK:https://codeforces.com/gym/105184;比如最终答案是:10...01...12...23...3,则其值为1*10^?+(1...1)*10^?+(2...2)*10^?...;因此,如何求2....2这个值(长度为1e9),使用矩阵优化DP,DP定义为:DP[i]:长度为i的2...2的大......
  • 【问题解答】渲染农场的 10 个常见问题,助您轻松上手
    渲染农场是3D动画和效果图设计领域的强大工具。它们提供使复杂场景和动画所需的计算能力。在本文中,小编将解答有关渲染农场的10个常见问题,为初学者和经验丰富的专业人士提供见解和指导。1.渲染农场值得吗?渲染农场有多种益处,尤其是在提高3D项目的效率和节约成本方面。这里以......
  • MySQL常见问题解答:初学者常遇到的疑惑与解决方案
    MySQL是一种常用的关系型数据库管理系统,用于存储和管理大量的数据。对于初学者来说,可能会遇到一些问题和困惑。下面是一些常见问题的解答和解决方案:1.安装和配置MySQL您可以按照以下步骤进行操作:1.1下载MySQL安装包:您可以从MySQL官方网站MySQL::下载MySQL社区服务......
  • [博客迁移20190713]题解 P4169 【[Violet]天使玩偶/SJY摆棋子】
    《算法竞赛》书上例题(可惜原书没代码)天使玩偶,一道好题。(书p243)我就来谈谈自己的想法吧!而总有人在这种明明可以离线处理的三维偏序问题上投机取巧。如:KDtree。蒟蒻想说,KDtree在这题复杂度是不对的。虽有剪枝,可是还是有可能遍历整棵树的(期望复杂度不靠谱)对上述看法有争议的,请跳......
  • QT | 文件读写过程中丢失的 OD OA 问题解决
    今天发现QT以文本方式(QIODevice::Text)写入二进制0x0A会出现问题,写入的是一个字节(实际应该是两个字节),结果在Zed上看,显示是2个字节。明显每个0x0A前都多了个0x0D,导致我的bin文件全部都错位了期望的效果应该是原来按照字节流的形式输出文本时,ofstream会自动将输......
  • Codeforces Round 927 (Div. 3) D. Card Game 题解 贪心
    CardGame题目描述Twoplayersareplayinganonlinecardgame.Thegameisplayedusinga32-carddeck.Eachcardhasasuitandarank.Therearefoursuits:clubs,diamonds,hearts,andspades.Wewillencodethemwithcharacters‘C’,‘D’,‘H’,......
  • 题解:CF1975G Zimpha Fan Club
    \(\text{Link}\)题意给你两个长度分别为\(n,m\)的字符串\(s,t\),其中仅包含小写字母、-和*,你需要将-替换为任意小写字母,*替换为任意小写字母构成的字符串(可以为空串),问是否可以使得\(s'=t'\)。\(n,m\le2\times10^6\),12s。思路首先我们有工具:NTT优化带通配符的字符......
  • 2024 CCPC 全国邀请赛(山东)暨山东省大学生程序设计竞赛题解 A C F I K
    超时就是AC队第一次打ccpc比较菜蒟蒻只能做五题ProblemA.打印机算法:二分思路:二分时间每次check查看当前时间内所有打印机可以打印的个数是否符合条件注意二分的右边界为2e18ProblemC.多彩的线段2算法:组合数思路:将所有线段按照起点从左到右排序枚举线段每次将当......