【HNOI2011】数学作业(BZOJ 2326)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2326   设f[i]表示i的答案,那么 f[i] = f[i - 1] * 10 + i      (i < 10) f[i] = f[i - 1] * 100 + i    (  100<=i<=999) ……   我们发现N的范围很大所以要用矩阵加速递推: 然后也需要分段改变递推矩阵的系数。  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MID(x,y) ((x+y)>>1)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

typedef long long LL;

LL n, m;
const int MAX = 5;
struct Mat{
    int row, col;
    LL mat[MAX][MAX];
};
//initialize square matrix to unit matrix
Mat unit(int n){
    Mat A;
    A.row = A.col = n;
    memset(A.mat, 0, sizeof(A.mat));
    for (int i = 0; i < n; i ++)
        A.mat[i][i] = 1;
    return A;
}
//return A*B%mod
Mat mul(Mat A, Mat B, int mod){
    Mat C;
    C.row = A.row;
    C.col = B.col;
    for (int i = 0; i < A.row; i ++){
        for (int j = 0; j < B.col; j ++){
            C.mat[i][j] = 0;
            for (int k = 0; k < A.col; k ++)
                //注意这里要保证乘法不溢出,否则还需要设计特殊的乘法模
                C.mat[i][j] += A.mat[i][k] * B.mat[k][j];
            C.mat[i][j] %= mod;
        }
    }
    return C;
};
//return A^n%mod
Mat exp_mod(Mat A, LL n, int mod){
    Mat res = unit(A.row);
    while(n){
        if (n & 1LL){
            res = mul(res, A, mod);
        }
        A = mul(A, A, mod);
        n >>= 1;
    }
    return res;
}
Mat A, res;

void changeA(LL p){
    A.col = A.row = 3;
    A.mat[0][0] = p % m;   A.mat[0][1] = 1;    A.mat[0][2] = 0;
    A.mat[1][0] = 0;    A.mat[1][1] = 1;    A.mat[1][2] = 1;
    A.mat[2][0] = 0;    A.mat[2][1] = 0;    A.mat[2][2] = 1;
}

void init(){
    res.col = 1;
    res.row = 3;
    res.mat[0][0] = 0;
    res.mat[1][0] = 1;
    res.mat[2][0] = 1;
    changeA(10);
}

int main(){
    cin >> n >> m;
    init();
    LL k1 = 0;
    LL k2 = 9;
    LL ct = 10;
    while(n >= k2){
        res = mul(exp_mod(A, k2-k1, m), res, m);
        k1 = k2;
        if (k2 == 99999999999999999)
            k2 = 100000000000000001;
        k2 = k2 * 10 + 9;
        changeA(10*ct);
        ct *= 10;
    }
    if (n > k1)
        res = mul(exp_mod(A, n-k1, m), res, m);
    cout << res.mat[0][0] << endl;
	return 0;
}
 
posted @ 2013-04-02 12:40  AbandonZHANG  阅读(116)  评论(0编辑  收藏  举报