题解 P3216 【[HNOI2011]数学作业】
Description
题目链接:Luogu 3216
小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:
给定正整数
数据范围:
Solution
我们设前
发现第
转移矩阵为:
但是我们发现,指数
注意:合并时,必须用转移矩阵的若干次方左乘答案矩阵!
时间复杂度:
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=4;
int mod;
void upd(int &x,int y) {
(x+=y)>=mod&&(x-=mod);
}
struct Matrix {
int n,A[N][N];
Matrix(int _n=0) {n=_n,memset(A,0,sizeof(A));}
void operator ~ () {
for(int i=0;i<n;++i) A[i][i]=1;
}
Matrix operator * (const Matrix &b) const {
Matrix ret(n);
for(int i=0;i<n;++i) for(int j=0;j<n;++j) for(int k=0;k<n;++k) {
upd(ret.A[i][k],1LL*A[i][j]*b.A[j][k]%mod);
}
return ret;
}
Matrix operator ^ (const long long &b) const {
Matrix ret(n),x=*this; ~ret;
for(long long p=b;p;p>>=1,x=x*x) if(p&1) ret=ret*x;
return ret;
}
};
Matrix ans(3);
void calc(long long p,long long b) {
Matrix x(3);
x.A[0][0]=p%mod,x.A[0][1]=x.A[0][2]=x.A[1][1]=x.A[1][2]=x.A[2][2]=1;
ans=(x^b)*ans;
}
int main() {
long long n;
scanf("%lld%d",&n,&mod);
~ans;
long long r=10;
while(r<=n) calc(r,r-(r/10)),r*=10;
calc(r,n-r/10+1);
printf("%d\n",ans.A[0][2]);
return 0;
}