有一棵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
题解
记dp[i]表示距离为i的点的个数,dp[i]+=dp[i-d[j]],类似于斐波那契,可用矩阵乘法优化。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<ctime>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#define mod 1000000007
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=102;
int ans[N+2][N+2],a[N+2][N+2],dp[N+2];
int n,x,d[100005];
void mul(int a[N+2][N+2],int b[N+2][N+2],int ans[N+2][N+2])
{
int tmp[N+2][N+2];
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
{
tmp[i][j]=0;
for(int k=1;k<=N;k++)
tmp[i][j]=(tmp[i][j]+(ll)a[i][k]*b[k][j]%mod)%mod;
}
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
ans[i][j]=tmp[i][j];
}
int main()
{
n=read();x=read();if (x==0) return printf("1"),0;
for (int i=1;i<=n;i++)
{
int D=read();
d[i]=D;
a[1][D]++;
a[N][D]++;
}
a[N][N]=1;
dp[0]=1;int sum=1;
for (int i=1;i<=100;i++)
{
a[i+1][i]=1;
for (int j=1;j<=n;j++)
if (d[j]<=i) dp[i]=(dp[i]+dp[i-d[j]])%mod;
sum=(sum+dp[i])%mod;
if (i==x) return printf("%d",sum),0;
}
x-=100;
for (int i=1;i<=N;i++) ans[i][i]=1;
while (x)
{
if (x&1) mul(ans,a,ans);
x>>=1;
mul(a,a,a);
}
int answer=0;dp[101]=sum;
for (int i=1;i<=N;i++)
{
int q=N-i-1;
if (q<0) q=101;
answer=(answer+(ll)ans[N][i]*dp[q]%mod)%mod;
}
printf("%d",answer);
return 0;
}