bzoj2326 [HNOI2011]数学作业

分析:设f[i]为1~i组成的数,可以得到f[i] = f[i-1] * 10^k + i.对于一个序列求第n项,一般可以用矩阵乘法来加速,但是每一个矩阵只能对应一个不变的递推式,这个式子中的k会变,那怎么办呢?那么在1~9,10~99,100~999每一次构造一个矩阵就好了,具体的矩阵如下:

f(i + 1)         f(i)      10^k,1,1

    i        =     i - 1    *    0, 1, 1

    1         1      0, 0, 1

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

using namespace std;

long long n, m,i,ans[10][10],temp[10][10],t[10][10];

void mul1()
{
    memset(t, 0, sizeof(t));
    for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 3; j++)
            for (int k = 1; k <= 3; k++)
            {
        t[i][j] += ans[i][k] * temp[k][j];
        t[i][j] %= m;
            }
    memcpy(ans, t, sizeof(ans));
}

void mul2()
{
    memset(t, 0, sizeof(t)); 
    for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 3; j++)
            for (int k = 1; k <= 3; k++)
            {
        t[i][j] += temp[i][k] * temp[k][j];
        t[i][j] %= m;
            }
    memcpy(temp, t, sizeof(temp));
}

void qpow(long long b)
{
    while (b){
        if (b & 1)
            mul1();
        b >>= 1;
        mul2();
    }
}

int main()
{
    scanf("%lld%lld", &n, &m);
    ans[1][3] = 1;
    for (i = 1; i <= (n + 1) / 10; i *= 10)
    {
        memset(temp, 0, sizeof(temp));
        ans[1][2] = i % m;
        temp[1][1] = (i * 10) % m;
        temp[2][1] = temp[2][2] = temp[3][2] = temp[3][3] = 1;
        qpow(i * 9);
    }
    if (i <= n)
    {
        memset(temp, 0, sizeof(temp));
        ans[1][2] = i % m;
        temp[1][1] = i * 10 % m;
        temp[2][1] = temp[2][2] = temp[3][2] = temp[3][3] = 1;
        qpow(n - i + 1);
    }
    printf("%lld\n", ans[1][1]); 

    return 0;
}

 

posted @ 2017-09-18 20:36  zbtrs  阅读(245)  评论(0编辑  收藏  举报