【codeforces 514E】Darth Vader and Tree

【题目链接】:http://codeforces.com/problemset/problem/514/E

【题意】

无限节点的树;
每个节点都有n个儿子节点;
且每个节点与其第i个节点的距离都是ai;
问你与根节点的距离不超过x的节点个数;

【题解】

考虑一个非常不靠谱的DP方程
f[i]=∑(f[i-j]*cnt[j]);
这里f[i]表示与根节点的距离为i的节点个数;
cnt[j]表示ai的值中为j的ai的个数;(即与儿子节点距离为j的边的个数);
因为ai最大值为100,所以j∈[1..100]
i∈[0..x]
求和就是答案了;
但x有1e9的规模;
需要优化;
矩阵!
这里先把f[1..100]的值算出来,同时把f[1..100]累加起来->sum;
得到矩阵A
这里写图片描述
然后再构造一个系数矩阵B
这里写图片描述
cnt的意义如上;
这里之所以把sum加进去,是为了便于最后直接输出结果;
不然我们这样递推如果只得出f[x]的话,你没办法加起来;
前100列用于递推出f[i+1];
第100列用于求和∑f[1..i];

A×Bx100
最后答案直接输出右下角那个值a[101][101]就好;
sum一开始加上一个1;
因为本身也算.

【Number Of WA

0

【完整代码】

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define ps push_back
#define fi first
#define se second
#define rei(x) cin >> x
#define ms(x,y) memset(x,y,sizeof x)

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;

const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
const double pi = acos(-1.0);
const int N = 110;
const LL MOD = 1e9+7;

int n,x;
LL dp[N],cnt[N],sum;

const int G = 101;       //矩阵大小
struct MX
{
    int v[G+5][G+5];
    void O() { ms(v, 0); }
    void E() { ms(v, 0); for (int i = 1; i <= G; ++i)v[i][i] = 1; }
    void P()
    {
        for (int i = 1; i <= G; ++i)
        {
            for (int j = 1; j <= G; ++j)printf("%d ", v[i][j]); puts("");
        }
    }
    MX operator * (const MX &b) const
    {
        MX c; c.O();
        for (int k = 1; k <= G; ++k)
        {
            for (int i = 1; i <= G; ++i) if (v[i][k])
            {
                for (int j = 1; j <= G; ++j)
                {
                    c.v[i][j] = (c.v[i][j] + (LL)v[i][k] * b.v[k][j]) % MOD;
                }
            }
        }
        return c;
    }
    MX operator + (const MX &b) const
    {
        MX c; c.O();
        for (int i = 1; i <= G; ++i)
        {
            for (int j = 1; j <= G; ++j)
            {
                c.v[i][j] = (v[i][j] + b.v[i][j]) % MOD;
            }
        }
        return c;
    }
    MX operator ^ (LL p) const
    {
        MX y; y.E();
        MX x; memcpy(x.v, v, sizeof(v));
        int num[64+2],cnt = 0;
        while (p)
        {
            num[++cnt] = p&1;
            p>>=1;
        }
        for (int i =cnt;i>=1;i--)
        {
            y = y*y;
            if (num[i])
                y = y*x;
        }
        return y;
    }
}a,xishu;

int main()
{
    //freopen("F:\\rush.txt","r",stdin);
    ios::sync_with_stdio(false);
    rei(n),rei(x);
    rep1(i,1,n)
    {
        int d;
        rei(d);
        cnt[d]++;
    }
    dp[0] = 1;
    rep1(i,1,min(x,100))
        rep1(j,1,i)
            dp[i] = (dp[i]+(dp[i-j]*cnt[j])%MOD)%MOD;
    sum=1;
    rep1(i,1,min(x,100))
        sum=(dp[i]+sum)%MOD;
    if (x<=100)
        return cout << sum << endl,0;
    a.O();
    rep1(i,1,100)
        a.v[1][i] = dp[i];
    a.v[1][101]= sum;
    xishu.O();
    rep1(i,2,100)
        xishu.v[i][i-1] = 1;
    rep1(i,1,100)
        xishu.v[i][100]=xishu.v[i][101] = cnt[101-i];
    xishu.v[101][101] = 1;
    a = a*(xishu^(x-100));
    cout << a.v[1][101]<<endl;
    //printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}
posted @ 2017-10-04 18:44  AWCXV  阅读(102)  评论(0编辑  收藏  举报