题解 P3216 【[HNOI2011]数学作业】
第一篇题解!QwQ~
*这道题首先是要明白矩阵快速幂的作用:将1e18的N转换为可以用快速幂做的快速运算。。。
*其次是本题蒟蒻认为的一个坑点——被MOD过的LL类型的相乘虽然感觉上是不会“爆炸”的,但在本题和一些其它的矩阵类型题中是很有可能的,所以很需要一个Q_Mul函数来快速乘,防止LL类型爆炸。。。
*还有一个本题的坑点——需要将Ten的Ten[0],即0位数设为1,详情请看代码。
*本题的一个难点——需要用A[20]来存储每一中位数所需要的A矩阵
例如:若Ans此时为两位数,那我我们就需要一个A[2],即{{LL,LL,LL,LL},{LL,10^2,1,1},{LL,0,1,1},{LL,LL,0,1}}来作为 Ans乘的对象,是的Ans乘以A[2]了之后可以得到Ans的下一次处理后的数。
(代码有点。。。)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
long long Total,MOD;
inline long long Q_Mul(long long L,long long R,long long P)
{
L=(L%P+P)%P;
R=(R%P+P)%P;
long long Res=L*R-(long long)((long double)L/P*R+1e-8)*P;
return Res < 0?Res+P:Res;
}//快速乘,防止LL爆炸
struct Node{
long long Squ[4][4];
inline void Clear_S(long long X)
{
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
Squ[i][j]=X;
}//清空Node用
friend Node operator * (Node A,Node B){
Node Get;
Get.Clear_S(0);
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++){
Get.Squ[i][j]=(Get.Squ[i][j]%MOD+Q_Mul(A.Squ[i][k],B.Squ[k][j],MOD))%MOD;
}
return Get;
}//重载矩阵乘法,即两矩阵相乘
}A[20],Ans;//需要用来转换的矩阵以及我们的Ans
long long Ten[20];//其实没什么用,初始化A时可以用
inline long long read()
{
unsigned long long x=0,f=1;
char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}//快读,emm。。。
inline long long Fpow(long long x,long long y)
{
long long step=x;
long long ans=1;
while(y){
if(y&1)ans=ans*step;
y>>=1;
step=step*step;
}
return ans;
}//快速幂,算Ten时用
inline void Sta()
{
Total=read();MOD=read();
for(int i=1;i<=19;i++){
Ten[i]=Fpow(10,i);
A[i].Clear_S(1);
A[i].Squ[2][1]=0;A[i].Squ[1][1]=Ten[i];
A[i].Squ[3][1]=0;A[i].Squ[3][2]=0;
}//每一位数的A初始化
Ans.Clear_S(0);
Ans.Squ[3][1]=1;//Ans的初始化emm。。。
Ten[0]=1;//嗯
}//初始化
inline void Node_Pow(int X)
{
long long Sum;
if(X==(floor(log10(Total))+1)) Sum=(Total-Ten[X-1]+1);
else Sum=Ten[X]-Ten[X-1];//每次需要完成的快幂数Sum
while(Sum){
if(Sum&1) Ans=A[X]*Ans;
Sum>>=1;
A[X]=A[X]*A[X];
}//矩阵快速幂
}
int main()
{
Sta();//整体初始化(蒟蒻的习惯)
for(int i=1;i<=floor(log10(Total))+1;i++){
Node_Pow(i);//完成每一位数的矩阵快速幂
}
printf("%lld",Ans.Squ[1][1]);//输出答案
return 0;
}
*非常OJBKQwQ~