一棵树,每个结点有n个儿子,该第i个儿子到父节点的距离为d[i],问离根节点距离不超过x的结点有多少个,结果对1e9+7取模。
之前写的了,忘记是参考哪个大牛的博客了:以下是他的分析
首先注意到每个di <= 100数据很小, 如果用ti表示所有n中分支中长度为i的个数, 那么就有t[1~100],
* 用dp[i]表示到根节点长度为i的点的个数, 那么不难发现状态转移方程
* dp[x] = dp[x - 1]*t[1] + dp[x - 2]*t[2] + ... + dp[x - 100]*t[100]
* 显然对于这个线性的状态转移方程, 预先处理计算出dp[0~99]即可递推后边的值
* 最后的结果是S[x] = dp[0] + dp[1] + ... + dp[x]
* 所以可以建立矩阵转移,
#include<bits/stdc++.h> using namespace std; #define LL __int64 #define maxn 102 #define MOD 1000000007 struct Matrix { LL a[maxn][maxn]; Matrix() { memset(a,0,sizeof(a)); for(int i=1;i<maxn;++i) a[i][i]=1; } }; Matrix operator *(Matrix A,Matrix B) { Matrix C; for(int i=1;i<maxn;++i) for(int j=1;j<maxn;++j) { C.a[i][j]=0; for(int k=1;k<maxn;++k) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j]%MOD)%MOD; } return C; } Matrix pow(Matrix A,int n) { Matrix res; while(n) { if(n&1) res=res*A; A=A*A; n>>=1; } return res; } LL t[maxn],dp[100005]; int main() { int x,n,i,j; scanf("%d%d",&n,&x); memset(t,0,sizeof(t)); for(i=1;i<=n;++i) { int tem; scanf("%d",&tem); ++t[tem]; } memset(dp,0,sizeof(dp)); LL s=1; dp[0]=1; for(i=1;i<=100;++i) { for(j=1;i-j>=0;++j) dp[i]=(dp[i]+dp[i-j]*t[j]%MOD)%MOD; if(i!=100) s=(s+dp[i])%MOD; } LL ans=0; if(x<=100) for(i=0;i<=x;++i) ans=(ans+dp[i])%MOD; else { Matrix A; memset(A.a,0,sizeof(A.a)); for(i=1;i<=100;++i) {A.a[i][1]=t[i];A.a[i][101]=t[i];} A.a[i][1]=0,A.a[i][101]=1; for(i=1;i<=99;++i) A.a[i][i+1]=1; A=pow(A,x-99); for(i=1;i<=100;++i) ans=(ans+dp[100-i]*A.a[i][101])%MOD; ans=(ans+s*A.a[i][101])%MOD; } printf("%I64d\n",ans); return 0; }