noip模拟赛 蒜头君的兔子

分析:直接暴力算有30分,像斐波那契那样推式子算有60分,如果想要得到100分就要用一种数列题的常见优化--矩阵了.

      当前的兔子数和十年内的兔子数有关,我们需要1个1*11的矩阵,来记录当前为0岁、1岁、2岁......兔子的数量,同时还需要一个快速幂矩阵进行计算.由于一年后a[1] = a[0],a[2] = a[1],......,a[10] = a[9],a[0] = a[1] + a[2] + a[3] + ...... + a[10],很容易构造出矩阵来.

      因为矩阵比较复杂,还是推荐用结构体来写.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int mod = 1000000007;
int t;
long long print,sum;

struct node
{
    int n, m;
    long long a[20][20];
    node()
    {
        memset(a, 0, sizeof(a));
        n = 0;
        m = 0;
    }
}s,p,ans;

node mul(node a, node b)
{
    node c;
    c.n = a.n;
    c.m = b.m;
    for (int i = 0; i < a.n; i++)
        for (int j = 0; j < b.m; j++)
            for (int k = 0; k < a.m; k++)
            {
                c.a[i][j] += (a.a[i][k] * b.a[k][j]) % mod;
                c.a[i][j] %= mod;
            }
    return c;
}

node qpow(node a, int b)
{
    node t;
    t.n = 11;
    t.m = 11;
    for (int i = 0; i < 11; i++)
        t.a[i][i] = 1;
    while (b)
    {
        if (b & 1)
            t = mul(t, a);
        a = mul(a, a);
        b >>= 1;
    }
    return t;
}

int main()
{
    scanf("%d", &t);
    s.n = 1;
    s.m = 11;
    s.a[0][1] = 1;
    p.n = 11;
    p.m = 11;
    for (int i = 1; i <= 9; i++)
    {
        p.a[i][0] = 1;
        p.a[i - 1][i] = 1;
    }
    p.a[10][0] = 1;
    ans = mul(s, qpow(p, t - 1));
    for (int i = 0; i <= 10; i++)
        sum = (sum + ans.a[0][i]) % mod;
    printf("%lld\n", sum);

    return 0;
}

 

posted @ 2017-09-26 21:22  zbtrs  阅读(308)  评论(0编辑  收藏  举报