ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI Online #2 提高组] 游戏

2021-10-10 14:03:23  阅读:111  来源: 互联网

标签:std NOI 游戏 int ll long Online include define


我们发现其实恰好并不太好做。
我们可以考虑大力容斥。
这个类型就很像二项式反演的做法

我们设\(f(i)\)表示钦定\(i\)回合分出平局,其他位置不管的方案数,\(g(i)\)表示恰好有\(i\)回合分出平局的方案数。
那么就有\(f(n) = \sum_{i = n}^m\binom{i}{n}g(i)\)
二项式反演一手则有
\(g(n) = \sum_{i = n}^m (-1) ^ {i - n}\binom{i}{n}f(i)\)

那么我们只要考虑怎么求\(f(i)\)即可。

那么我们考虑\(f(i,j)\)表示以\(i\)为根的子树中,存在\(j\)对祖先-后代关系,且颜色不同。

有两种转移:
1.子树结果合并,树形背包。
2.根节点选择一个没选过的配对。

注意到我们\(dp\)时只固定了颜色不同的祖先-后代关系,其他的点应该直接自由组合。

#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long 
#define mod 998244353
#define MOD 998244353
#define N 5005

using std::min;

std::vector<int>e[5005];

char s[N];
int n;
ll fr[N];
ll c[N][N];
ll f[N][N],g[N];
int siz[N],siz1[N];
//
inline void dfs(int u,int fa){
//	std::cout<<u<<" "<<fa<<std::endl;
	siz[u] = 1,siz1[u] = (s[u] - '0');
	f[u][0] = 1;
	for(int i = 0;i < e[u].size();++i){
		int v = e[u][i];
		if(v == fa)continue;
		dfs(v,u);
		for(int i = 0;i <= siz[u] + siz[v];++i)
		g[i] = 0;
		for(int i = 0;i <= std::min(siz[u],n / 2);++i)
		for(int j = 0;j <= std::min(siz[v],n / 2 - i);++j)
		g[i + j] = (g[i + j] + f[u][i] * f[v][j]) % mod;
		for(int i = 0;i <= siz[u] + siz[v];++i)
		f[u][i] = g[i];
		siz[u] += siz[v],siz1[u] += siz1[v];
	}
	for(int i = std::min(siz1[u],siz[u] - siz1[u]);i;--i)
	if(s[u] == '1')
	f[u][i] = (f[u][i] + f[u][i - 1] * (siz[u] - siz1[u] - (i - 1))) % mod;
	else
	f[u][i] = (f[u][i] + f[u][i - 1] * (siz1[u] - (i - 1))) % mod;
}

int main(){
	scanf("%d",&n);
	fr[0] = 1;
	scanf("%s",s + 1);
	for(int i = 1;i <= n;++i)
	fr[i] = fr[i - 1] * i % mod,c[i][0] = 1;
	c[0][0] = 1;
	for(int i = 1;i <= n;++i)
	for(int j = 1;j <= n;++j)
	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
	for(int i = 1;i < n;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,0);
	for(int i = 0;i <= n / 2;++i)
	f[1][i] = f[1][i] * fr[n / 2 - i] % mod;
	for(int i = 0;i <= n / 2;++i){
		ll ans = 0;
		for(int j = i;j <= n / 2;++j)
		if((j - i) & 1)ans = (ans - c[j][i] * f[1][j] % mod + mod) % mod;
		else
		ans = (ans + c[j][i] * f[1][j]) % mod;
		std::cout<<ans<<std::endl;
	}
}

标签:std,NOI,游戏,int,ll,long,Online,include,define
来源: https://www.cnblogs.com/dixiao/p/15389302.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有