矩阵快速幂 [HNOI2011]数学作业
问题 G: [HNOI2011]数学作业
时间限制: 2 Sec 内存限制: 128 MB
好不容易有一道自己想出来的水题~~
先说一下怎么构造矩阵吧,
b: 10^? 1 1
0 1 1
0 0 1
a: 0 0 0
0 0 0
1 0 0
我不证了。。→_→。。自己乘一下试试,我如果这么写,千万别乘反了。。
下面说说那个10^?, 对于个位数只移一位,而两位数移两位。。只要判断一下你乘到多少位的数就行了,
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll n,m,xp[20];
struct node
{
ll f[3][3];
node(){memset(f,0,sizeof(f));}
}a,b,ans;
node operator *(node a,node b)
{
node c=node();//
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
{
c.f[i][j]=(c.f[i][j]+((a.f[i][k]%m)*(b.f[k][j]%m))%m)%m;
}
return c;
}
void get(ll x)
{
b=node();
b.f[0][0]=(xp[x]%m)*10;
b.f[0][1]=b.f[0][2]=b.f[1][1]=b.f[1][2]=b.f[2][2]=1;
}
void cheng(ll x)
{
while(x)
{
if(x&1)ans=b*ans;
b=b*b;
x/=2;
}
}
int main()
{
scanf("%lld%lld",&n,&m);
xp[0]=1;
for(int i=1;i<=19;i++)xp[i]=xp[i-1]*10;
a.f[2][0]=1;
for(int i=0;i<3;i++)for(int j=0;j<3;j++)ans.f[i][j]=(i==j);
for(int i=0;;i++)
{
ll k=9*xp[i];
get(i);
if(k>=n)break;
n-=k;
cheng(k);
}
cheng(n);
ans=ans*a;
printf("%lld",ans.f[0][0]%m);
}