1 条题解
-
0
自动搬运
来自洛谷,原作者为

yijan
我结束了!搬运于
2025-08-24 22:21:10,当前版本为作者最后更新于2020-04-25 12:27:48,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
由于 Latex 挂了,建议到 Luogu 博客或者 这里 查看。
我们记 “恰好有 次非平局” 的方案数是 ,“钦定有 次非平局” 的方案数是 。发现这是一个二项式反演的形式,由二项式反演有公式:(不会可以百度)
$$f(n)=\sum\limits_{i=n}^m{i\choose n}g(i)\Leftrightarrow g(n)=\sum\limits_{i=n}^m(-1)^{i-n}{i\choose n}f(i) $$所以我们只要求出 就做完了这个题。我们可以 dp 求出 ,设 表示 子树内钦定选择了 对点,这 对点均呈 祖先 - 子孙 的关系(也就是这 局钦定会比出胜负)。于是发现这东西可以直接树形背包算。
转移就是正常的树形背包,最后还需要考虑钦定这个点和某个后代的情况,这种情况的转移就是从子树内未被钦定的点中选择一个点。
然后我交上去的代码多输出了个 考试的时候没看到 /kk
#include "iostream" #include "algorithm" #include "cstring" #include "cstdio" #include "cmath" #include "vector" #include "map" #include "set" #include "queue" using namespace std; #define MAXN 5006 //#define int long long #define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i) #define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i) #define pii pair<int,int> #define fi first #define se second #define mp make_pair #define pb push_back #define eb emplace_back #define vi vector<int> #define all(x) (x).begin() , (x).end() #define mem( a ) memset( a , 0 , sizeof a ) typedef long long ll; #define P 998244353 int n; int A[MAXN]; int head[MAXN] , to[MAXN << 1] , nex[MAXN << 1] , ecn; void ade( int u , int v ) { to[++ ecn] = v , nex[ecn] = head[u] , head[u] = ecn; } int dp[MAXN][MAXN] , siz[MAXN] , sz[MAXN]; int pd[MAXN]; void dfs( int u , int fa ) { siz[u] = 1 , sz[u] = A[u]; dp[u][0] = 1; for( int i = head[u] , v ; i ; i = nex[i] ) { v = to[i]; if( v == fa ) continue; dfs( v , u ); rep( k , 0 , siz[u] + siz[v] ) pd[k] = 0; rep( j , 0 , min( siz[u] , n / 2 ) ) if( dp[u][j] ) rep( k , 0 , min( siz[v] , n / 2 - j ) ) if( dp[v][k] ) pd[j + k] = ( pd[j + k] + dp[u][j] * 1ll * dp[v][k] % P ) % P; rep( k , 0 , siz[u] + siz[v] ) dp[u][k] = pd[k]; siz[u] += siz[v] , sz[u] += sz[v]; } per( i , min( sz[u] , siz[u] - sz[u] ) , 1 ) dp[u][i] = ( dp[u][i] + dp[u][i - 1] * 1ll * ( ( A[u] ? ( siz[u] - sz[u] ) : ( sz[u] ) ) - ( i - 1 ) ) % P ) % P; } int J[MAXN] , iJ[MAXN]; int Pow( int x , int a ) { int ret = 1; while( a ) { if( a & 1 ) ret = 1ll * ret * x % P; x = 1ll * x * x % P , a >>= 1; } return ret; } int C( int a , int b ) { return J[a] * 1ll * iJ[b] % P * iJ[a - b] % P; } void solve() { cin >> n; J[0] = iJ[0] = 1; rep( i , 1 , MAXN - 1 ) J[i] = J[i - 1] * 1ll * i % P , iJ[i] = Pow( J[i] , P - 2 ); rep( i , 1 , n ) scanf("%1d",A + i); int u , v; rep( i , 2 , n ) scanf("%d%d",&u,&v) , ade( u , v ) , ade( v , u ); dfs( 1 , 1 ); int re = 0; rep( i , 0 , n / 2 + 1 ) dp[1][i] = dp[1][i] * 1ll * J[n / 2 - i] % P; rep( i , 0 , n / 2 ) { re = 0; rep( j , i , n / 2 ) re += C( j , i ) * 1ll * ( ( j - i & 1 ) ? P - 1 : 1 ) % P * dp[1][j] % P , re %= P; printf("%d ",re); } } signed main() { // freopen("match.in","r",stdin); // freopen("match.out","w",stdout); // int T;cin >> T;while( T-- ) solve(); solve(); }
- 1
信息
- ID
- 5502
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者