「闲话随笔」「DROI」Round 2

「闲话随笔」「DROI」Round 2

点击查看目录

今日推歌推啥啊?

题挺好玩的。

P9373 「DROI」Round 2 构造与取模

发现 \(k, n - k\) 即为一组正确构造,\(k \ge n - k\) 时无解。

为啥无解啊?不难发现 \(k \ge n - k\)\(k \ge \dfrac{n}{2}\),则一组合法构造 \((x, y)\) 必然满足 \(x, y \le k\),你模数比 \(k\) 小你余数怎么等于 \(k\)

P9374 「DROI」Round 2 单图

不难发现当一个点出入度均不为零时,指向它的一个点和它指向的一个点之间连或不连一条边构成的两种图本质相同,因此一个合法图的任意一个点出入度必须至少有一个为零。

这个结论是错的,因为存在两点环。不存在两点环时这个结论是正确的。

那么枚举两点环数量 \(i\),考虑分别计算两点环方案数 \(f(i)\) 和无两点环的图的方案数 \(g(i)\)。则答案为:

\[\sum_{i = 1}^{\left\lfloor\frac{n}{2}\right\rfloor}\dbinom{n}{2i}f(2i)g(n - 2i) \]

首先考虑两点环计数,依次选取两个点即可,但是依次选会带有本来不该有的顺序,所以要除去 \(i!\)

\[\begin{aligned} f(2i) &= \frac{1}{i!}\prod_{j = 1}^{i}\dbinom{2i - 2j + 2}{2}\\ &= \frac{1}{i!}\prod_{j = 1}^{i}\frac{(2i - 2j + 2)(2i - 2j + 1)}{2}\\ &= \frac{1}{i!}\prod_{j = 1}^{i}(i - j + 1)\prod_{j = 1}^{i}(2i - 2j + 1)\\ &= \prod_{j = 1}^{i}(2j + 1)\\ \end{aligned} \]

然后计算无两点环的图方案数 \(g(i)\)。我们把图分成「有入度」和「无入度」两类点,显然方案数就是两类点之间随便连边的方案数。注意不能一条边不连,因为前一类点定义是「有入度」。

\[\begin{aligned} g(i) &= \sum_{j = 0}^{i}\dbinom{i}{j}(2^{i - j} - 1)^{j} \end{aligned} \]

点击查看代码
const ll N = 1010;
namespace SOLVE {
	ll n, P, c[N][N], f[N], g[N], ans;
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline ll FastPow (ll a, ll b) {
		ll ans = 1;
		while (b) {
			if (b & 1) ans = ans * a % P;
			a = a * a % P, b >>= 1;
		}
		return ans;
	}
	inline void Init () {
		_for (i, 0, 1000) {
			c[i][0] = 1;
			_for (j, 1, i) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P;
		}
		f[0] = 1;
		_for (i, 1, 500) f[i] = f[i - 1] * (2 * i + 1) % P;
		_for (i, 0, 1000) {
			g[i] = 0;
			_for (j, 0, i) g[i] = (g[i] + c[i][j] * FastPow (FastPow (2, i - j) - 1, j) % P) % P;
		} 
		return;
	}
	inline void In () {
		n = rnt ();
		return;
	}
	inline void Solve () {
		ans = g[n];
		_for (i, 1, n / 2) ans = (ans + c[n][2 * i] * f[i - 1] % P * g[n - 2 * i] % P) % P;
		return;
	}
	inline void Out () {
		printf ("%lld\n", ans);
		return;
	}
}

P9375 「DROI」Round 2 划分

考虑爆搜,感觉状态数很大,但是其实是跑不满的。所以我们直接把状态哈希一下然后记忆化搜索即可。

好像是之前有一场校内模拟赛有类似的题目,所以考场上也有这种直觉,只是不太信自己。当时那道题还是场切了的,这回就没切,真是越学越倒退。

哈希时取模超时了,所以贺了题解的神奇写法。

点击查看代码
const ll N = 130, P = 1e6 + 3;
namespace SOLVE {
	ll n, m, a[N], c[N], b[N][N], vis[P];
	class STA {
	public:
		ll len, cnt[N];
		inline ll GetHash () {
			ll tmp = 0;
			for_ (i, n, 1) tmp = (tmp * (c[i] + 1) + cnt[i]);
			return tmp;
		}
	} qwq;
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline ll Dfs (STA s) {
		ll h = s.GetHash ();
		if (vis[h] > -1) return vis[h];
		ll mx = 0;
		_for (i, 1, n) {
			if (!s.cnt[i]) continue;
			STA st = s;	st.len -= i, --st.cnt[i];
			mx = std::max (mx, Dfs (st) + b[st.len + 1][s.len]);
		}
		vis[h] = mx;
		return mx;
	}
	inline void In () {
		qwq.len = n = rnt ();
		_for (i, 1, n) a[i] = rnt ();
		_for (i, 1, n) qwq.cnt[i] = c[i] = rnt (), m += i * c[i];
		return;
	}
	inline void Solve () {
		if (m != n) return;
		memset (vis, -1, sizeof (vis));
		_for (i, 1, n) {
			_for (j, 1, i) {
				ll l = 0, r = 0;
				_for (k, j, i) {
					ll q1 = std::abs(a[k] - a[j]), q2 = std::abs(a[i] - a[k]);
					l += ((ll)(sqrt (q1)) * (ll)(sqrt (q1)) == q1);
					r += ((ll)(sqrt (q2)) * (ll)(sqrt (q2)) == q2);
				}
				b[j][i] = l * r;
			}
		}
		return;
	}
	inline void Out () {
		printf ("%lld\n", (m == n) ? Dfs (qwq) : -1);
		return;
	}
}

P9376 「DROI」Round 2 进制与操作

有空再补。

posted @ 2023-05-30 21:06  K8He  阅读(76)  评论(0编辑  收藏  举报