Codeforces 514E Darth Vader and Tree【Dp+矩阵快速幂优化】

2/10/2017来源:ASP.NET技巧人气:822

E. Darth Vader and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output

When Darth Vader gets bored, he sits down on the sofa, closes his eyes and thinks of an infinite rooted tree where each node has exactly n sons, at that for each node, the distance between it an its i-th left child equals to di. The Sith Lord loves counting the number of nodes in the tree that are at a distance at most x from the root. The distance is the sum of the lengths of edges on the path between nodes.

But he has got used to this activity and even grew bored of it. 'Why does he do that, then?' — you may ask. It's just that he feels superior knowing that only he can solve this PRoblem.

Do you want to challenge Darth Vader himself? Count the required number of nodes. As the answer can be rather large, find it modulo 109 + 7.

Input

The first line contains two space-separated integers n and x (1 ≤ n ≤ 105, 0 ≤ x ≤ 109) — the number of children of each node and the distance from the root within the range of which you need to count the nodes.

The next line contains n space-separated integers di (1 ≤ di ≤ 100) — the length of the edge that connects each node with its i-th child.

Output

Print a single number — the number of vertexes in the tree at distance from the root equal to at most x.

Examples Input
3 3
1 2 3



Output
8





Note

Pictures to the sample (the yellow color marks the nodes the distance to which is at most three)

题目大意: 有一棵树,最开始就一个根节点,每个节点都有N个儿子,这个节点距离每个儿子的距离为di(1<=di<=100),问你距离根节点距离小于等于X的节点个数有多少个。 思路: 1、如果对于统计个数,我们考虑dp,设定dp【i】表示距离根节点距离为i的节点个数。 那么不难推出状态转移方程:dp【i】=Σdp【i-j】*len【j】; 2、显而易见,直接dp是会超时的,考虑优化,既然我们有了递推式,那么我们不妨介入矩阵优化。 然后矩阵快速幂就能够做到O(LogX)的时间复杂度。 3、既然有了dp递推式,那么矩阵的构造也就不难了: ①因为最大长度di==100,那么我们不妨将矩阵构造为101*101的大小,最后一行用来转移sum.因为我们要求的是Σdp【i】(0<=i<=X),而不是dp【X】; ②那么接下来预处理出dp【0~100】; ③那么有: ③对应求Sum【X】的时候,将第二个矩阵按照幂次增加即可。 Ac代码:
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll __int64
#define mod 1000000007
typedef struct Matrix
{
    ll mat[105][105];
}matrix;
matrix A,B,tmp,ans;
ll len[105];
ll dp[100000];
Matrix matrix_mul(matrix a,matrix b)
{
    matrix c;
    memset(c.mat,0,sizeof(c.mat));
    ll i,j,k;
    for(ll i=0;i<101;i++)
    {
        for(ll j=0;j<101;j++)
        {
            for(ll k=0;k<101;k++)
            {
                c.mat[i][j]=(c.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod)%mod;
            }
        }
    }
    return c;
}
Matrix matrix_quick_power(matrix a,ll k)//矩阵快速幂0.0
{
    matrix b;
    memset(b.mat,0,sizeof(b.mat));
    for(ll i=0;i<101;i++)
    b.mat[i][i]=1;//单位矩阵b
    while(k)
    {
        if(k%2==1)
        {
            b=matrix_mul(a,b);
            k-=1;
        }
        else
        {
            a=matrix_mul(a,a);
            k/=2;
        }
    }
    return b;
}
int main()
{
    ll n,m;
    while(~scanf("%I64d%I64d",&n,&m))
    {
        memset(len,0,sizeof(len));
        memset(dp,0,sizeof(dp));
        for(ll i=1;i<=n;i++)
        {
            ll x;
            scanf("%I64d",&x);
            len[x]++;
        }
        dp[0]=1;
        for(ll i=1;i<=100;i++)
        {
            for(ll j=1;j<=i;j++)
            {
                dp[i]+=dp[i-j]*len[j];
                dp[i]%=mod;
            }
        }
        ll presum=0;
        for(ll i=1;i<=m&&i<=100;i++)presum+=dp[i],presum%=mod;
        if(m<=100)
        {
            printf("%I64d\n",presum+1);
        }
        else
        {
            memset(A.mat,0,sizeof(A.mat));
            memset(tmp.mat,0,sizeof(tmp.mat));
            for(ll i=0;i<100;i++)tmp.mat[i][0]=dp[i+1];
            tmp.mat[100][0]=presum+1;
            for(ll i=0;i<99;i++)
            {
                A.mat[i][i+1]=1;
            }
            for(ll i=0;i<100;i++)A.mat[99][i]=len[100-i];
            for(ll i=0;i<100;i++)A.mat[100][i]=len[100-i];
            A.mat[100][100]=1;
            B=matrix_quick_power(A,m-100);
            B=matrix_mul(B,tmp);
            printf("%I64d\n",(B.mat[100][0]+mod)%mod);
        }
    }
}