矩阵快速幂 [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);
}
posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(145)  评论(0编辑  收藏  举报