BZOJ-2326 数学作业 矩阵乘法快速幂+快速乘

2326: [HNOI2011]数学作业
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1564 Solved: 910
[Submit][Status][Discuss]

Description
这里写图片描述

Input

Output

Sample Input

Sample Output

HINT

Source

题解:
矩乘快速幂,构造矩阵:
这里写图片描述
其中k为位数,所以分段进行快速幂;
1~9;10~99;100~999;….

开始4A6W,然后加了快速乘AC了,但是YveH做的比我慢一些,没用快速乘也A了。。可能姿势不对?

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
long long n,m;
long long A[4][4],B[4][4];


long long quick_mul(long long x,long long y,long long p)
{
    if (y==0) return 0;
    if (y==1) return x%p;
    long long re;
    re=quick_mul(x,y>>1,p);
    if ((y&1)==1) return (re+re+x)%p;
             else return (re+re)%p;
}

void quick_pow(long long a[4][4],long long b[4][4],long long S[4][4])
{
    long long tmp[4][4];
    for(int i=1;i<=3;i++)
       for(int j=1;j<=3;j++)
       {
          tmp[i][j]=0;
          for(int k=1;k<=3;k++)
             tmp[i][j]=(tmp[i][j]+quick_mul(a[i][k],b[k][j],m))%m;
         }
    for(int i=1;i<=3;i++)
       for(int j=1;j<=3;j++)
          S[i][j]=tmp[i][j];
}
void work(long long t,long long end)
{
    B[1][1]=t;
    B[2][1]=B[2][2]=B[3][1]=B[3][2]=B[3][3]=1;
    B[1][2]=B[1][3]=B[2][3]=0;
    long long y=end-t/10+1;
    while(y)
    {
        if(y&1) quick_pow(A,B,A);
        quick_pow(B,B,B);
        y>>=1;
    }
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=3;i++) A[i][i]=1;
    long long t=10;
    while(n>=t) work(t,t-1),t*=10;
    work(t,n);
    printf("%lld",A[3][1]);
    return 0;
}
posted @ 2016-02-19 18:44  DaD3zZ  阅读(231)  评论(0编辑  收藏  举报