题面比较文艺。
大意:给一棵树,这个树有无限个节点。对于每个点,都有n个儿子,第i个儿子与这个点的距离为 di 。问这棵树有多少个点离根的距离不超过x。
首先可以列出一个DP: f[i]=∑nj=1f[i−dj] ,边界是 f[0]=1 。
似乎不是那么好做。但是注意到, di<=100 ,这意味着DP可以简化一下,变成连续的; f[i]=∑100j=1f[i−j]∗cnt[j] ,其中j表示有多少条边权为j的边。要求的答案是 ∑xi=0f[i] ,cnt可以预处理出来,接下来就是很经典的矩阵快速幂啦!
令 s[i]=∑1<=j<=if[j] 。设
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for(int i = a , _ = b ; i >= _ ; i --)
#define For(i,a,b) for(int i = a , _ = b ; i < _ ; i ++)
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
const int mod = 1000000007;
typedef long long ll;
inline int mul(int a , int b) { return (ll) a * b % mod; }
struct Matrix {
int a[101][101];
Matrix() { memset(a , 0 , sizeof a) ; }
friend Matrix operator*(Matrix&A , Matrix&B) {
Matrix C = Matrix();
For (i , 0 , 101) For (j , 0 , 101) For (k , 0 , 101)
(C.a[i][j] += mul(A.a[i][k] , B.a[k][j])) %= mod;
return C;
}
}A , B , T;
int n , x , cnt[101] , f[101];
void input() {
n = rd() , x = rd();
rep (i , 1 , n) cnt[rd()] ++;
}
void init() {
f[0] = 1;
rep (i , 1 , 100)
rep (j , 1 , i) (f[i] += mul(f[i - j] , cnt[j])) %= mod;
}
void solve() {
init();
if (x <= 100) {
int ans = 0;
rep (i , 0 , x) (ans += f[i]) %= mod;
printf("%d\n" , ans);
return;
}
For (i , 0 , 100) A.a[0][i] = f[i + 1] , (A.a[0][100] += f[i + 1]) %= mod;
For (i , 0 , 99 ) B.a[i + 1][i] = 1;
B.a[100][100] = 1;
For (i , 0 , 100) B.a[i][99] = B.a[i][100] = cnt[100 - i];
For (i , 0 , 101) T.a[i][i] = 1;
for (x -= 100;x;x >>= 1) {
if (x & 1) T = T * B;
B = B * B;
}
A = A * T;
printf("%d\n" , (A.a[0][100] + 1) % mod);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return 0;
}