有一棵n叉树,深度是无限的,每个结点有n个儿子。从左到右编号为1到n号儿子,第i号儿子离该结点的距离是di。现在要统计一下距离根结点不超过x的结点有多少个。
数字比较大对 109 + 7 取余后输出。
样例解释:
图中黄色的结点是距离根不超3的。
Input
单组测试数据。
第一行有两个整数n和x (1≤n≤10^5,0≤x≤10^9),表示每个结点的儿子数目,以及上文提到的x。
第二行有n个整数d1,d2,d3,…,dn (1≤di≤100)。
Output
输出结果占一行。
Input示例
样例输入1
3 3
1 2 3
Output示例
样例输出1
8
思路:
假设f(i)为扩张一次后增加的距离根节点的长度为i的节点的数量,则:
f(i) = f(i-1) * cnt1 + f(i-2) * cnt2 + f(i-3) * cnt3 + ... + f(i-mx) * cntmx. (mx为n个儿子中距离自己最远的长度)。
这是个递推关系,因此考虑用矩阵乘法来做。
对于例子中的输入,构造矩阵如下, 左边为相乘的矩阵,右边初始值从上致下依次为f(0), f(-1), f(-2), f(-3)。
相乘后得到 。这个新矩阵的值从上到下依次为f(1), f(0), f(-1), f(-2)+f(-3)。
相乘矩阵中增加的最后一列,目的就是为了保存扩张后不再发生变化的f(i).
将左边这个相乘矩阵取x次幂,再与相乘,然后将每一行的值加起来就行。
可以观察到,只要取相乘矩阵x次幂的最左边那列的和就行了。
矩阵相乘可以用矩阵快速幂来做。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int n,m,d[100005],mx;
struct Matrix
{
int a[105][105];
void clear(int n)
{
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
{
a[i][j] = 0;
}
}
}
void unit(int n)
{
clear(n);
for (int i = 0; i <= n; i++)
{
a[i][i] = 1;
}
}
}a;
void mul(Matrix &c, Matrix a, Matrix b)
{
c.clear(mx);
for (int i = 0; i <= mx; i++)
{
for (int j = 0; j <= mx; j++)
{
for (int k = 0; k <= mx; k++)
{
c.a[i][j] += (ll)a.a[i][k] * b.a[k][j] % MOD;
c.a[i][j] %= MOD;
}
}
}
}
Matrix q_pow(Matrix x, int y)
{
Matrix ans;
ans.unit(mx);
while (y)
{
if (y & 1)
{
mul(ans, ans, x);
}
mul(x, x, x);
y >>= 1;
}
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
mx = 0;
for (int i = 0; i < n; i++)
{
scanf("%d", &d[i]);
mx = max(mx, d[i]);
}
for (int i = 0; i < n; i++)
{
a.a[0][d[i]-1]++;
}
for (int i = 1; i <= mx; i++)
{
a.a[i][i-1]++;
}
a.a[mx][mx] = 1;
a = q_pow(a, m);
int result = 0;
for (int i = 0; i <= mx; i++)
{
result = (result + a.a[i][0]) % MOD;
}
printf("%d", result);
return 0;
}