Codeforces 514E 矩阵快速幂

来源:互联网 发布:linux 局域网传文件 编辑:程序博客网 时间:2024/05/19 02:01
/*有这样一棵树,每个节点都有n(1~100000)个儿子,伸向n个儿子的边从左到右分别为di(1~100)这棵树是无穷延伸的,求距离根节点距离小于等于x(1e9)的节点数目解法:好题,算是寒假第一题,手生,没做出来都解法是矩阵快速幂设dp[i]为距离根节点距离恰好为i的数目,首先很好想到dp[i+j] += dp[i]*cnt[j]那么这样就是一个很明显的矩阵构造矩阵的构造比较有技巧矩阵A(1x101)[dp[1] , dp[2] , ... , dp[100] , sigma(dp[i],i=0~100) ]矩阵B(101x101)[0 0 0 ... 0 0 cnt[100] cnt[100]][1 0 0 ... 0 0 cnt[99]  cnt[99] ][0 1 0 ... 0 0 cnt[98]  cnt[98] ][0 0 1 ... 0 0 cnt[97]  cnt[97] ]...[0 0 0 ... 0 1 cnt[1]   cnt[1]  ][0 0 0 ... 0 0 0        0       ]*/#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <iostream>#include <set>using namespace std;#define ll long long#define pb push_back#define PII pair<ll,ll>#define ALL(x) (x).begin(),(x).end()const int N=111;//matrix size#define TYPE intint A[111][111];int B[111][111];int C[111][111];int tmp[111][111];const int MAXN = 101111;int d[MAXN];const int MOD = 1e9+7.5;void printfm(TYPE A[N][N],int n,int m){    for(int i=0;i<n;i++){        for(int j=0;j<m;j++){            printf("%d%c",A[i][j],(j==m-1)?'\n':' ');        }    }    printf("\n");}void mul(TYPE A[N][N],TYPE B[N][N],TYPE t[N][N],int n,int m,int l)//A 为n*m的矩阵,B为m*l的矩阵,t为结果矩阵{    TYPE tmp[N][N];//为了防止冲突    for(int i=0;i<n;i++){        for(int j=0;j<l;j++){            tmp[i][j]=0;            for(int k=0;k<m;k++)                tmp[i][j]=(tmp[i][j]+1LL*A[i][k]*B[k][j]%MOD)%MOD;        }    }    for(int i=0;i<n;i++)        for(int j=0;j<l;j++)            t[i][j]=tmp[i][j];}void expo(TYPE p[N][N],TYPE e[N][N],int k,int n)//P为n*n的矩阵,k为计算k次幂,e为结果矩阵{    if(k!=1){        for(int i = 0; i < n; ++i)            for(int j = 0; j < n; ++j)                e[i][j] = (i == j);        while(k){            if(k&1) mul(e,p,e,n,n,n);            mul(p,p,p,n,n,n);            k>>=1;        }    }else{        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                e[i][j]=p[i][j];    }}int dp[111];int cnt[111];int main(){    //freopen("in.txt","r",stdin);    int n,x;    scanf("%d%d",&n,&x);    for(int i=1;i<=n;i++){        scanf("%d",&d[i]);        cnt[d[i]]++;    }    dp[0]=1;    for(int i=0;i<=100;i++){        for(int j=0;j<=100;j++){            dp[i+j] += 1LL*dp[i]*cnt[j]%MOD;            dp[i+j]%=MOD;        }    }    int sum=1;    for(int i=0;i<100;i++) A[0][i]=dp[i+1],sum=(sum+dp[i+1])%MOD;    A[0][100] = sum;    for(int i=0;i<100;i++) B[i][99] = B[i][100] = cnt[100-i];    B[100][100] = 1;    for(int i=1;i<=99;i++) B[i][i-1] = 1;    if(x<=100){        int ans=0;        for(int i=0;i<=x;i++) ans=(ans+dp[i])%MOD;        printf("%d\n",ans);    }else{        //printfm(B,10,10);        expo(B,tmp,x-100,101);        mul(A,tmp,C,1,101,101);        printf("%d\n",C[0][100]);    }    return 0;}

0 0
原创粉丝点击