道县找人做网站,百度关键词热度,那些网站专门做棋牌推广的,广告设计教程题意#xff1a;一棵n2mn2mn2m个点的树#xff0c;mmm个白点和mmm个黑点。对于k∈[0,n]k\in [0,n]k∈[0,n]#xff0c;求出 把点黑白两两配对使得恰好有kkk对点有祖孙关系 的方案数 模998244353998244353998244353。 n≤5000n \leq 5000n≤5000
见到恰好考虑容斥#xff0…题意一棵n2mn2mn2m个点的树mmm个白点和mmm个黑点。对于k∈[0,n]k\in [0,n]k∈[0,n]求出 把点黑白两两配对使得恰好有kkk对点有祖孙关系 的方案数 模998244353998244353998244353。
n≤5000n \leq 5000n≤5000
见到恰好考虑容斥并不
我们钦定kkk对点有祖孙关系其他点随便匹配
这个是个经典的树上背包设fu,kf_{u,k}fu,k表示uuu的子树中钦定kkk对的方案数
直接把子树搓起来然后算上匹配根的方案
看上去是O(n3)O(n^3)O(n3)实际上控下上下界可以做到O(n2)O(n^2)O(n2)
证明是一次的复杂度是∑x,y∈son(u)sizxsizy\sum_{x,y\in son(u) }siz_xsiz_y∑x,y∈son(u)sizxsizy抽象成把所有跨子树的点对遍历一次显然一个点对只会在lca处被遍历
算完后记得乘上其它点随便匹配的方案即一个阶乘
然后二项式反演即可
#include iostream
#include cstdio
#include cstring
#include cctype
#include vector
#define MAXN 5005
using namespace std;
inline int read()
{int ans0;char cgetchar();while (!isdigit(c)) cgetchar();while (isdigit(c)) ans(ans3)(ans1)(c^48),cgetchar();return ans;
}
const int MOD998244353;
inline int add(const int x,const int y){return xyMOD? xy-MOD:xy;}
typedef long long ll;
inline int qpow(int a,int p)
{int ans1;while (p){if (p1) ans(ll)ans*a%MOD;a(ll)a*a%MOD;p1;}return ans;
}
char s[MAXN];
vectorint e[MAXN];
int col[MAXN],cnt[MAXN][2],lim[MAXN],dp[MAXN][MAXN];
void dfs(int u,int f)
{cnt[u][col[u]]1;dp[u][0]1; for (int i0;i(int)e[u].size();i)if (e[u][i]!f){dfs(e[u][i],u);cnt[u][0]cnt[e[u][i]][0],cnt[u][1]cnt[e[u][i]][1];for (int xmin(cnt[u][0],cnt[u][1]);x1;x--)for (int kmax(x-lim[u],1);kxkmin(cnt[e[u][i]][0],cnt[e[u][i]][1]);k)dp[u][x](dp[u][x](ll)dp[u][x-k]*dp[e[u][i]][k])%MOD;lim[u]min(cnt[u][0],cnt[u][1]); }for (int xmin(cnt[u][0],cnt[u][1]);x0;x--)dp[u][x1](dp[u][x1](ll)(cnt[u][col[u]^1]-x)*dp[u][x])%MOD;
}
int fac[MAXN],finv[MAXN],ans[MAXN];
inline int C(const int n,const int m){return (ll)fac[n]*finv[m]%MOD*finv[n-m]%MOD;}
int main()
{int nread();int mn/2;scanf(%s,s1);fac[0]1;for (int i1;in;i) fac[i](ll)fac[i-1]*i%MOD;finv[n]qpow(fac[n],MOD-2);for (int in-1;i0;i--) finv[i](ll)finv[i1]*(i1)%MOD;for (int i1;in;i) col[i]s[i]-0;for (int i1;in;i){int u,v;uread(),vread();e[u].push_back(v),e[v].push_back(u);}dfs(1,0);for (int i0;im;i) dp[1][i](ll)dp[1][i]*fac[m-i]%MOD;for (int i0;im;i)for (int ji;jm;j)ans[i]add(ans[i],(ll)(((j^i)1)? (MOD-C(j,i)):C(j,i))*dp[1][j]%MOD);for (int i0;im;i) printf(%d\n,ans[i]);return 0;
}