题解:P11856 [CSP-J2022 山东] 吟诗

这道题给当时只学了两个月 C++ 的我偌大的震撼,时隔多年,满是回忆。

发现正着数太难想,反着想反而更加清晰。于是思路是先计算出所有不含妙手的诗的数量,再用总方案数 \(10^N\) 减去不含妙手的数量,得到答案。

我们用状态压缩 DP 来记录后缀和状态,定义:

  • \(dp[i][st]\) 表示前 \(i\) 个数字构成后缀和状态为 \(st\) 的方案数。
  • 状态 \(st\) 用二进制表示:若第 \(k\) 位为 \(1\),则表示存在一个后缀和为 \(k+1\);这里只记录不超过 \(X+Y+Z\) 的后缀和。

对每个位置 \(i\) 和状态 \(st\) 以及枚举当前数字 \(d\)\(1 \le d \le 10\)),更新后缀和状态为:

\[t = \left\{ \begin{array}{l} t \mathrel{|}= (1 << (d-1)) \quad \text{(如果 $d \le X+Y+Z$)} \\ \text{对于 $st$ 中每个存在的后缀和 $s$(对应二进制第 $s-1$ 位为1),若 $s+d \le X+Y+Z$,则} \quad t \mathrel{|}= (1 << (s+d-1)) \end{array} \right. \]

状态转移方程为:

\[dp[i+1][t] \mathrel{+}= dp[i][st] \]

但如果新状态 \(t\) 中同时存在后缀和 \(Z\)\(Y+Z\)\(X+Y+Z\)(即对应二进制位均为 \(1\)),说明序列中已经出现妙手,此转移应舍去。

统计所有 \(dp[N][st]\) 得到不含妙手的序列数 \(cnt\) ,答案即为:

\[ans = 10^N - cnt \quad (\text{对 }998244353 \text{ 取模}) \]

时间复杂度 \(O(10 \times N \times 2^{X+Y+Z})\)

#include<bits/stdc++.h>
using namespace std;
#define MAXN 50
#define MOD 998244353
#define ST 1 << 18
#define int long long
int dp[MAXN][ST];

signed main() {
	int N, X, Y, Z;
	cin >> N >> X >> Y >> Z;
	int sum = X + Y + Z;
	int lim = (1 << sum);
	for (int i = 0; i < MAXN; i++) {
		for (int j = 0; j < lim; j++) {
			dp[i][j] = 0;
		}
	}
	dp[0][0] = 1;
	int tot = 1;
	for (int i = 0; i < N; i++) {
		tot = (tot * 10) % MOD;
	}

	for (int i = 0; i < N; i++) {
		for (int st = 0; st < lim; st++) {
			if(dp[i][st] == 0) continue;
			for (int d = 1; d <= 10; d++) {
				int t = 0;
				if(d <= sum)
					t |= (1 << (d - 1));
				for (int bit = 0; bit < sum; bit++) {
					if ((st >> bit) & 1) {
						int cur = bit + 1;
						int ns = cur + d;
						if(ns <= sum) {
							t |= (1 << (ns - 1));
						}
					}
				}
				if( (t & (1 << (Z - 1))) && (t & (1 << ((Y + Z) - 1))) && (t & (1 << (sum - 1))) ) continue;
				dp[i+1][t] = (dp[i+1][t] + dp[i][st]) % MOD;
			}
		}
	}

	int cnt = 0;
	for (int st = 0; st < lim; st++) {
		cnt = (cnt + dp[N][st]) % MOD;
	}

	int ans = tot - cnt;
	if(ans < 0) ans += MOD;
	cout << ans % MOD << "\n";
	return 0;
}

posted @ 2025-03-08 09:12  薛儒浩  阅读(166)  评论(0)    收藏  举报