Codeforces 514E Darth Vader and Tree DP + 矩阵快速幂

题目大意:

给定n和x, (n <= 10^5, x <= 10^9) 表示现在有一颗完全n叉树, 根节点为起始点, 然后给定n个di分别表示每个对应的分支的距离, (1 <= di <= 100), 然后对于所有的点, 求其中到根节点的距离不超过x的节点的个数, 由于数字可能很大, 对最后的结果模上10^9 + 7之后输出


大致思路:

思路写在代码注释里了


代码如下:

Result  :  Accepted     Memory  :  852 KB     Time  :  1045 ms

/*
 * Author: Gatevin
 * Created Time:  2015/2/25 11:49:15
 * File Name: poi~.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

/*
 * 首先注意到每个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]
 * 所以可以建立矩阵转移, 由于
 * {dp[x], dp[x - 1], ... , dp[x - 99], S[x]} * |  t[1]  1 0 ... 0 t[1]  |
 *                                              |  t[2]  0 1 ... 0 t[2]  |
 *                                              |............... 1 t[3]  |
 *                                              | t[100] 0 0 ... 0 t[100]|
 *                                              |    0   0 0 ... 0   1   |
 * = {dp[x + 1], dp[x], dp[x - 1], ... dp[x - 98], S[x + 1]}
 * 所以对于转移矩阵求快速幂即可, 很普通的矩阵快速幂, 想到dp的转移方程就很容易想到了
 */

const lint mod = 1000000007LL;
int n, x, t[110];

struct Matrix
{
    lint a[110][110];
    Matrix()
    {
        memset(a, 0, sizeof(a));
        for(int i = 1; i <= 101; i++)
            a[i][i] = 1;
    }
};

Matrix operator + (Matrix m1, Matrix m2)
{
    Matrix ret;
    for(int i = 1; i <= 101; i++)
        for(int j = 1; j <= 101; j++)
            ret.a[i][j] = (m1.a[i][j] + m2.a[i][j]) % mod;
    return ret;
}

Matrix operator * (Matrix m1, Matrix m2)
{
    Matrix ret;
    for(int i = 1; i <= 101; i++)
        for(int j = 1; j <= 101; j++)
        {
            ret.a[i][j] = 0;
            for(int k = 1; k <= 101; k++)
                ret.a[i][j] = (ret.a[i][j] + m1.a[i][k]*m2.a[k][j] % mod) % mod;
        }
    return ret;
}

Matrix quick_pow(Matrix base, int pow)
{
    Matrix I;
    while(pow)
    {
        if(pow & 1)
            I = I*base;
        base = base*base;
        pow >>= 1;
    }
    return I;
}

lint dp[110];

int main()
{
    scanf("%d %d", &n, &x);
    int tt;
    memset(t, 0, sizeof(t));
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &tt);
        t[tt]++;
    }
    Matrix A;
    memset(A.a, 0, sizeof(A.a));
    for(int i = 1; i <= 100; i++)
        A.a[i][1] = A.a[i][101] = t[i];
    for(int i = 1; i < 100; i++)
        A.a[i][i + 1] = 1;
    A.a[101][101] = 1;
    memset(dp, 0, sizeof(dp));
    dp[0] = 1;
    for(int i = 1; i <= 100; i++)
        for(int j = 1; i - j >= 0 && j <= 100; j++)
            dp[i] = (dp[i - j]*t[j] + dp[i]) % mod;
    if(x <= 100)
    {
        lint ans = 0;
        for(int i = 0; i <= x; i++) ans = (ans + dp[i]) % mod;
        cout<<ans<<endl;
        return 0;
    }
    A = quick_pow(A, x - 99);
    lint S = 0;
    for(int i = 0; i <= 99; i++) S = (S + dp[i]) % mod;
    lint ans = 0;
    for(int i = 1; i <= 100; i++)
        ans = (ans + dp[100 - i]*A.a[i][101]) % mod;
    ans = (ans + S*A.a[101][101]) % mod;
    cout<<ans<<endl;
    return 0;
}


你可能感兴趣的:(tree,codeforces,and,矩阵快速幂,514E,Darth,Vader)