CF514E
先考虑暴力的 DP,设 fi 表示到根节点距离恰好为 i 的节点数量,则有
fi=n∑j=1fi−dj
初值为 f0=1,最终求的是 x∑i=0fi。
注意到 di≤100,有很多相同的转移,于是记 cnti 表示 {d} 中 i 的出现次数,则有
fi=100∑j=1cntj×fi−j
x 最大有 109 级别并且这个式子看着就能矩阵快速幂优化,于是设 sumi 表示 f 的前缀和,将 f 的前 100 个元素暴力求出,然后构造一个 101×101 的矩阵:
[1cnt1cnt2cnt3cnt4⋯cnt1000cnt1cnt2cnt3cnt4⋯cnt10001000⋯000100⋯000010⋯000001⋯0⋮⋮⋮⋮⋮⋱⋮0⋯00010]×[sumi−1fi−1fi−2fi−3fi−4fi−5⋮fi−100]=[sumififi−1fi−2fi−3fi−4⋮fi−99]
然后矩阵快速幂优化即可。
时间复杂度 O(1003logx)。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105, mod = 1e9 + 7;
int n, m;
int cnt[N];
int g[N], sum[N];
struct mat {
int a[N][N];
void clear() { memset(a, 0, sizeof a); }
void init() { clear(); for (int i = 0; i <= 100; ++i) a[i][i] = 1; }
mat operator * (const mat &x) const {
mat res; res.clear();
for (int i = 0; i <= 100; ++i)
for (int j = 0; j <= 100; ++j)
for (int k = 0; k <= 100; ++k)
res.a[i][j] = (res.a[i][j] + 1ll * a[i][k] * x.a[k][j] % mod) % mod;
return res;
}
} f, trans;
mat qpow(mat x, int y) {
mat res; res.init();
while (y) {
if (y & 1) res = res * x;
x = x * x;
y >>= 1;
}
return res;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1, x; i <= n; ++i) scanf("%d", &x), ++cnt[x];
g[0] = sum[0] = 1;
for (int i = 1; i < 100; ++i) {
for (int j = 1; j <= min(i, 100); ++j) g[i] = (g[i] + 1ll * g[i - j] * cnt[j] % mod) % mod;
sum[i] = (sum[i - 1] + g[i]) % mod;
}
if (m < 100) return printf("%d", sum[m]), 0;
trans.clear();
trans.a[0][0] = 1;
for (int i = 1; i <= 100; ++i) trans.a[0][i] = trans.a[1][i] = cnt[i];
for (int i = 2; i <= 100; ++i) trans.a[i][i - 1] = 1;
f.clear();
f.a[0][0] = sum[99];
for (int i = 1; i <= 100; ++i) f.a[i][0] = g[100 - i];
mat ans = qpow(trans, m - 99) * f;
printf("%d", ans.a[0][0]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话