[AGC022F] Checkers 题解

考虑神秘建树。我们将所有 \(B\)\(A\) 连边,就会又双叒叕形成一棵以最后剩下的那个点为根的有根树。我们考虑每个点对于根节点的影响。

首先,发现每个点对父亲的贡献一定是 \(2x^i\)\(-2x^i\),所以传递到根节点时,贡献即为 \(c_i2^{d_i}x^i\),其中 \(c_i\in\{-1,1\},d_i\)\(i\) 点的深度。由于 \(x\) 巨大,所以我们观察到本题关键结论:

两个方案最终答案不同 等价于 两个方案对应的 \(c_i,d_i\) 不同。

\(d_i\) 和树的形态有关,待会儿 \(dp\) 的时候再说,我们先进一步分析 \(c_i\)

我们模拟一下一只点 \(u\) 的行进过程:

  1. 以他的儿子们为跳板,取反 \(sn_u\) 次。
  2. 被他的父亲当跳板,然后消失。

所以可知对于一个点 \(u\),恰好有 \(\lfloor\frac{sn_u}2\rfloor\) 个儿子被取反奇数次。所以得到:

  1. \(c_{rt}=(-1)^{sn_{rt}}\)
  2. 对于非叶子节点 \(u\),有 \(\lfloor\frac{sn_u}2\rfloor\) 个儿子节点满足 \(c_v=(-1)^{sn_v}c_u\),其余的儿子节点 \(w\) 满足 \(c_w=(-1)^{sn_v+1}c_u\)

由于 \(d\) 的缘故,我们考虑一层一层的求答案,所以我们 \(dp\) 的第一维 \(i\) 表示当前枚举到树的第几层,第二维 \(j\) 表示当前放置了多少个点。

如何将 \(c\) 融入进来呢?考虑记 \(e_i=-[sn_i\bmod 2]c_i\),所以若对应 \(c_i\) 相等,则两棵树每层的 \(\sum e_i\) 也相等,所以 \(\sum[e_i=1]\)\(\sum[e_i=-1]\) 也相等。这样,我们就可以将第三维 \(k\) 设为这一层 \(\sum e_i\) 的总和。

总结一下,我们设 \(f_{i,j,k}\) 表示枚举到第 \(i\) 层,放置了 \(j\) 个点,这一层的 \(\sum e_i=k\) 的总方案数。

那么我们先枚举该层的点数 \(t\),再设其中 \(h\) 个点的 \(c_i=1\),则有:

\[f_{i,j,k}=\sum_{t=1}^j\sum_{h=0}^t\binom jt\binom thf_{i-1,j-t,2k-t+h}[|2k-t+h|\le t] \]

时间复杂度超高,\(O(n^5)\),不过够用了。

#include<bits/stdc++.h>
using namespace std;
const int N=55,p=1e9+7;
int n,dp[N][N][N*2],C[N][N],ans;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n,dp[1][1][n]=dp[1][1][n+1]=C[0][0]=1;
	for(int i=0;i<=n;C[++i][0]=1)
		for(int j=1;j<=i;j++)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
	for(int i=2;i<=n;i++) for(int j=i;j<=n;j++) for(int k=j-n;k<=n-j;k++)
		for(int t=1;t<=j;t++) for(int c=0;c<=t;c++) if(abs(2*(k+c)-t)<=t)
			dp[i][j][k+n]=(dp[i][j][k+n]+1ll*dp[i-1][j-t][2*(k+c)-t+n]*C[j][t]%p*C[t][c])%p;
	for(int i=1;i<=n;i++) ans=(ans+dp[i][n][n])%p;
	return cout<<ans,0;
}
posted @ 2025-03-25 14:39  长安一片月_22  阅读(17)  评论(0)    收藏  举报