ABC249E

\(f(i,j)\) 表示压缩后长度为 \(i\),原串长度为 \(j\) 的方案数。

则最终答案就是 \(\sum_{i=1}^{n-1}f(i,n)\)

考虑转移,枚举下一段的长度 \(k\),设长度的位数为 \(x\),则有 \(f(i+1+x,j+k)\gets f(i+1+x,j+k)+25\times f(i,j)\)

初值 \(f(0,0)=\dfrac{26}{25}\),因为第一段连续的字母是可以随便选的。

考虑对于固定的 \(x\),它对应的能更新到的是一段区间,能轻松用前缀和优化成 \(\mathcal O(n^2\log_{10} n)\)

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3005;
int n, p;
int pw[6] = {1, 10, 100, 1000, 10000 ,100000};
int f[N][N], sum[N][N];

int qpow(int x, int y) {
	int res = 1;
	while (y) {
		if (y & 1) res = 1ll * res * x % p;
		x = 1ll * x * x % p;
		y >>= 1;
	}
	return res;
}

int main() {
	scanf("%d%d", &n, &p);
	f[0][0] = 1ll * qpow(25, p - 2) * 26 % p;
	for (int i = 1; i <= n; ++i) sum[0][i] = f[0][0];
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			for (int k = 1; k <= 4; ++k) {
				if (i - k - 1 < 0) break;
				int x = max(0, j - pw[k - 1] + 1), y = max(0, j - pw[k] + 1);
				f[i][j] += 1ll * (((sum[i - k - 1][x] - sum[i - k - 1][y]) % p + p) % p) * 25 % p;
				f[i][j] %= p;
			}
			sum[i][j + 1] = (sum[i][j] + f[i][j]) % p;
		}
	}
	int ans = 0;
	for (int i = 1; i < n; ++i) ans = (ans + f[i][n]) % p;
	printf("%d", ans);
	return 0;
}
posted @ 2022-11-09 21:44  Kobe303  阅读(14)  评论(0编辑  收藏  举报