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;
}