11.17比赛题解

A. 圣诞树

和度数相关的数题可以考虑 prufer 序列。

prufer 序列的性质是,一个数在其中出现次数加一是其度数。

如果称一个点上孔的数量为 \(a_i\),称一种情况中 i 点的度数是 \(d_i\),那么我们的答案就是:

\[\displaystyle\sum_{\sum {d_i - 1 = n - 2}} \binom{n - 2}{d_1 - 1} \binom{n - 2 - (d_1 - 1)}{d_2 - 1} ..... \binom{b_n - 1}{b_n - 1} \prod_{i = 1}^n a_i^{\underline{d_i}} \]

可以发现,前面的组合数相乘的部分就是:

\[(n - 2)!\sum_{\sum {d_i - 1 = n - 2}} \prod\frac{1}{(d_i - 1)!} \]

考虑把后面两项合并:

\[(n - 2)!\sum_{\sum {d_i - 1 = n - 2}} \prod\frac{a_i!}{(d_i - 1)!(a_i - d_i)!} \]

后面的东西很像组合数:

\[(n - 2)!\sum_{\sum {d_i - 1 = n - 2}} \prod a_i\frac{(a_i - 1)!}{(d_i - 1)!(a_i - d_i)!}\\ \Leftrightarrow (n - 2)!\prod a_i \sum_{\sum {d_i - 1 = n - 2}} \prod \binom{a_i - 1}{d_i - 1} \]

考虑组合意义,后面的东西就是:

\[(n - 2)!\prod a_i \sum_{\sum {d_i - 1 = n - 2}} \binom{\sum( a_i - 1)}{\sum (d_i - 1)}\\ \Leftrightarrow (n - 2)!\prod a_i \binom{\sum( a_i - 1)}{n - 2} \]

直接计算即可。

考场上模数不一定是质数,把 \((n - 2)!\) 消掉就行了。

代码
#include <bits/stdc++.h>
using namespace std;

namespace myb {
	
	using ll = long long;
	const int N = 2e5 + 10;
	const int Mod = 998244353;
	
	int a[N];
	
	void main() {
		int n;
		cin >> n;
		for (int i = 1;i <= n;i++) cin >> a[i];
		
		ll ans = 1;
		for (int i = 1;i <= n ;i++) ans = (__int128)ans * a[i] % Mod;
		ll S = 0;
		for (int i = 1;i <= n;i++) S += a[i] - 1;
//		cout << S << " " << ans << "\n";
		for (ll i = S;i > S - n + 2;i--) ans = (__int128)ans * i % Mod;
		cout << ans;
		// \prod a_i S!/(S - n - 2)!
	}
}

int main() {
	myb::main();
	return 0;
}

B. 序列

我们从值域的角度去想,如果我当前将所有大于 i 的数已经加进去了,现在我们要将所有的 i 插入这个序列中。

考虑如果现在我有 j 个连续段,那么如果我插入一个 i 不使段数增加,那么必须插在段尾,否则 i 会使段数增加。

我可以枚举不使段数增加的 i 有 x 个,剩下 \(a_i - x\) 个要插进原本连续段的两个数中间去,使连续段增加 \(a_i - x\) 个。

因为可以有两个 i 插入一个缝中,所以我们考虑插板法。

一共 \(a_i - x\) 个数,\(\sum_{t = i}^n a_t - j + x\) 个板。

则方程为

f[i][j + a[i] - x] += f[i][j] * C(j, x) * C(sum[i + 1] - j + x, sum[i + 1] + a[i] - j)

代码
#include <bits/stdc++.h>
using namespace std;

namespace myb {
	
    #define int long long
	using ll = long long;
	const int N = 55;
	const int Mod = 1e9 + 7;
	
	int a[N];
	
	ll f[N][N * N], C[3005][3005], sum[N];
	
	void main() {
        // cout << 114514;
		int n, k;
		cin >> n >> k;
		for (int i = 1;i <= n;i++) cin >> a[i];
		
        C[0][0] = 1;
		for (int i = 1;i <= 3000;i++) {
			C[i][0] = 1;
			for (int j = 1;j <= min(3000ll, i);j++) {
				C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
				C[i][j] %= Mod;
			}
		}
		
		for (int i = n;i >= 1;i--) sum[i] = sum[i + 1] + a[i];
//		cout << C[4][2] << '\n';
		
		f[n][a[n]] = 1;
		for (int i = n - 1;i >= 1;i--) {
			for (int j = 1;j <= k;j++) {
				for (int x = 0;x <= min(j, a[i]);x++) {
					if (j + a[i] - x > k) continue;
					if (sum[i + 1] + a[i] - j < 0) continue;
					if (sum[i + 1] + x - j < 0) continue;
					f[i][j + a[i] - x] += f[i + 1][j] * C[j][x] % Mod * C[sum[i + 1] + a[i] - j][sum[i + 1] - j + x] % Mod;
					f[i][j + a[i] - x] %= Mod;
				}
			}
		}
		cout << f[1][k];
	}
}

signed main() {
	freopen("seq.in", "r", stdin);
	freopen("seq.out", "w", stdout);
	myb::main();
	return 0;
}
posted @ 2025-11-17 18:55  yanbinmu  阅读(5)  评论(0)    收藏  举报