CF514E

先考虑暴力的 DP,设 fi 表示到根节点距离恰好为 i 的节点数量,则有

fi=nj=1fidj

初值为 f0=1,最终求的是 xi=0fi

注意到 di100,有很多相同的转移,于是记 cnti 表示 {d}i 的出现次数,则有

fi=100j=1cntj×fij

x 最大有 109 级别并且这个式子看着就能矩阵快速幂优化,于是设 sumi 表示 f 的前缀和,将 f 的前 100 个元素暴力求出,然后构造一个 101×101 的矩阵:

[1cnt1cnt2cnt3cnt4cnt1000cnt1cnt2cnt3cnt4cnt100010000001000000100000010000010]×[sumi1fi1fi2fi3fi4fi5fi100]=[sumififi1fi2fi3fi4fi99]

然后矩阵快速幂优化即可。

时间复杂度 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;
}
posted @   Kobe303  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示