Luogu P3216 [HNOI2011]数学作业 【矩阵快速幂】

题目描述

小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:

给定正整数 N 和 M ,要求计算 Concatenate (1 .. N) Mod M 的值,其中 Concatenate (1 .. N) 是将所有正整数 1, 2,...., N顺序连接起来得到的数。例如, N=13 , Concatenate (1 .. N)=12345678910111213 .小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。

输入输出格式

输入格式:

从文件input.txt中读入数据,输入文件只有一行且为用空格隔开的两个正整数N和M,其中30%的数据满足 1\leq N\leq1000000 ;100%的数据满足 1 \leq N \leq10^{18} 且 1 \leq M \leq10^{9} .

输出格式:

输出文件 output.txt 仅包含一个非负整数,表示 Concatenate (1 .. N) 的值。

输入输出样例

输入样例#1: 

13 13

输出样例#1: 

4

思路:根据题意易得递推式为F\left ( n \right )=F\left ( n-1 \right )*10^k+n \left(k为n的位数),直接构造矩阵是不可行的,因为矩阵中不存在10^k这种变量。考虑按位数构造矩阵,那这时候10^k就可以看作一个常数,注意不同位数的矩阵之间的衔接就没问题了。

\begin{pmatrix} 10^k & 1 & 0\\ 0 & 1 & 1\\ 0 & 0 & 1 \end{pmatrix} *  \begin{pmatrix} F\left ( n-1 \right ) \\ n \\ 1 \end{pmatrix} =  \begin{pmatrix} F\left ( n \right ) \\ n+1 \\ 1 \end{pmatrix} 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<climits>
using namespace std;
#define M(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef long long LL;
const int maxn = 100000+5;
struct Matrix {
    LL mat[3][3];
};
LL n,mod;
Matrix operator * (Matrix a,Matrix b) {
    Matrix res;
    for (int i=0;i<3;++i) {
        for (int j=0;j<3;++j) {
            res.mat[i][j]=0;
            for (int k=0;k<3;++k) {
                res.mat[i][j]=res.mat[i][j]+a.mat[i][k]*b.mat[k][j];
                res.mat[i][j]%=mod;
            }
        }
    }
    return res;
}
Matrix operator ^ (Matrix a,LL p) {
    Matrix res;
    M(res.mat,0);
    for (int i=0;i<3;++i) {
        res.mat[i][i]=1;
    }
    while(p) {
        if (p&1) {
            res=res*a;
        }
        a=a*a;
        p>>=1;
    }
    return res;
}
LL f[20];
int main() {


    scanf("%lld%lld",&n,&mod);
    Matrix A,ans;
    ans.mat[0][0]=0; ans.mat[0][1]=0;ans.mat[0][2]=0;
    ans.mat[1][0]=1;ans.mat[1][1]=0;ans.mat[1][2]=0;
    ans.mat[2][0]=1; ans.mat[2][1]=0;ans.mat[2][2]=0;
    A.mat[0][0]=10; 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;

    int k = 0;
    LL tp=n;
    while(tp) {
        tp/=10;
        ++k;
    }
    f[0]=1;
    for (int i=1;i<=k;++i) {
        f[i]=(f[i-1]<<3)+(f[i-1]<<1);
    }
    for (int i=1;i<=k;++i) {
        A.mat[0][0]=f[i]%mod;
        LL cnt;
        if (i==k) {
            cnt = n - f[i-1] + 1;
        }
        else {
            cnt = f[i] - f[i-1];
        }
        ans=(A^cnt)*ans;
    }
    printf("%lld\n",ans.mat[0][0]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38000095/article/details/81567938