514E (矩阵快速幂+DP)

来源:互联网 发布:武器发射工程 知乎 编辑:程序博客网 时间:2024/06/06 13:23

一棵树,每个结点有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 1000000007struct 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;}


 

 

0 0
原创粉丝点击