BZOJ 2326 数学作业(分段矩阵快速幂)

实际上,对于位数相同的连续段,可以用矩阵快速幂求出最后的ans,那么题目中一共只有18个连续段。

分段矩阵快速幂即可。

 

#include<cstdio>  
#include<iostream>  
#include<cstring>  
#include<cstdlib>  
#include<algorithm>  
#include<queue>  
#include<cmath>  
#define ll long long  
using namespace std;  
const int maxn=5;  
ll n,m;  
struct Mat  
{  
    ll mat[maxn][maxn];  
    Mat()  
    {  
        memset(mat,0,sizeof(mat));  
    }  
    Mat operator *(const Mat &b)  
    {  
        Mat c;  
        for(int k=1;k<=3;k++)  
        {  
            for(int i=1;i<=3;i++)  
            {  
                for(int j=1;j<=3;j++)  
                {  
                    c.mat[i][j]+=mat[i][k]*b.mat[k][j];  
                    c.mat[i][j]%=m;  
                }  
            }  
        }  
        return c;  
    }  
      
};    
Mat ans;  
Mat cal(ll k,ll t)  
{  
    Mat res;  
    Mat b;  
    ll y=t-k/10+1;  
    b.mat[1][1]=k%m;  
    b.mat[1][2]=b.mat[2][2]=b.mat[2][3]=b.mat[3][3]=b.mat[1][3]=1;  
    for(int i=1;i<=3;i++)res.mat[i][i]=1;  
    while(y)  {  
        if(y&1)res=res*b;  
        y>>=1;  
        b=b*b;  
    }  
    return res;  
}  
int main()  
{  
    ans.mat[3][1]=1;  
    scanf("%lld%lld",&n,&m);  
    ll t=10;  
    for(int i=1;i<=18;i++) {  
        ans=cal(t,t-1)*ans;  
        t*=10;  
        if(t>n)break;  
    }  
    ans=cal(t,n)*ans;  
    printf("%lld\n",ans.mat[1][1]);  
    return 0;  
}  
View Code

 

posted @ 2017-04-20 15:48  free-loop  阅读(186)  评论(0编辑  收藏  举报