SoundHound Programming Contest 2018 Masters Tournament 本戦 C - Not Too Close

随便写写。

考虑一个分层图 dp,记 f(i,j,k) 表示前 i 层,一共选了 j 个点,第 i 层选了 k 个点的方案数。

转移分两种情况:

  1. 层数 <=d

那么枚举下一层选的点的个数 l

那么层内连边方案为 2l(l1)2,两层之间连边是 (2k1)l

同时选取一个点作为下一层的点的方案是 (nj[i+1<=d]l[i+1=d])

  1. 层数 >d

枚举总点数,以及剩余点数,层内连边方案同理,同时剩余的点可以向非终点的点连边,方案同理。

于是状态是 O(n3),转移是 O(n),总复杂度为 O(n4)

#include <bits/stdc++.h>
typedef long long ll;
const int N = 160;
int n, D, mod;
ll f[N][N][N], binom[N][N], pw[N * N / 2 + 10];
ll fastpow(ll a, int b) {
	ll ret = 1;
	for(; b; b >>= 1, a = 1ll * a * a % mod) if(b & 1)
		ret = 1ll * ret * a % mod;
	return ret;
}
ll plus(ll a, ll b) {
	return a + b >= mod ? a + b - mod : a + b;
}
ll reduce(ll a, ll b) {
	return a - b < 0 ? a - b + mod : a - b;
}
ll mul(ll a, ll b) {
	return 1ll * a * b % mod;
}
 
int main() {
	scanf("%d%d%d", &n, &D, &mod);
	if(D == n - 1) {
		ll ans = 1;
		for(int i = 1; i <= n - 2; ++i) ans = mul(ans, i);
		printf("%lld\n", ans);
		return 0;
	}
	if(D == 1) {
		ll ans = fastpow(2ll, n * (n - 1) / 2 - 1);
		printf("%lld\n", ans);
		return 0;
	}
	pw[0] = 1;
	for(int i = 1; i <= n * n / 2; ++i) pw[i] = mul(2ll, pw[i - 1]);
	f[0][1][1] = 1, binom[0][0] = 1;
	for(int i = 1; i <= n; ++i) {
		binom[i][0] = binom[i][i] = 1;
		for(int j = 1; j < i; ++j) binom[i][j] = plus(binom[i - 1][j], binom[i - 1][j - 1]);
	}
	for(int i = 0; i < D; ++i) {
		for(int j = i; j <= n; ++j) {
			for(int k = 1; k <= j - i; ++k) if(f[i][j][k]) {
				// ll t = pw[k], pt = 1;
				ll pt = 1;
				for(int l = 1; j + l <= n - std::max(0, D - i - 1); ++l) {
					// ll t1 = pw[l * (l - 1) / 2], t2 = binom[n - j - (i + 1 <= D)][l - (i + 1 == D)],
						// t3 = mul(pt, t - 1);
					pt = mul(pt, pw[k] - 1);
					f[i + 1][j + l][l] = plus(f[i + 1][j + l][l], mul(f[i][j][k], mul(pw[l * (l - 1) / 2], mul(binom[n - j - (i + 1 <= D)][l - (i + 1 == D)], pt))));
					// pt = mul(pt, t - 1);
				}
			}
		}
	}
	ll ans = 0;
	for(int i = D; i <= n; ++i) for(int j = 1; j <= i - D; ++j) {
		// ll t1 = pw[(n - i) * (n - i - 1) / 2], t2 = pw[j * (n - i)];
		ans = plus(ans, mul(f[D][i][j], mul(pw[(n - i) * (n - i - 1) / 2], pw[j * (n - i)])));
	}
	printf("%lld\n", ans);
	return 0;
}
posted @   Nylch  阅读(31)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示