A simple math problem 【矩阵快速幂】


时间限制: 1 Sec   内存限制: 512 MB

题目描述

Given a number n, you should calculate 123456 . . . 11121314 . . . n module 11.

输入

A single line with an integer n (0 < n ≤ 10e18)  单组数据测试.

输出

Output one integer, 123456 . . . 11121314 . . . n module 11 

样例输入

1
20
21

样例输出

1
5
4

提示


1 ≡ 1( mod 11) 



1234567891011121314151617181920 ≡ 5( mod 11) 



123456789101112131415161718192021 ≡ 4( mod 11)

矩阵快速幂模板。。以前敲几次 都是手敲,老是有小bug。还是存个模板吧。

matrix muliti(matrix x,matrix y){
    matrix ret;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j){
            ret.a[i][j]=0;
            for(int k=0;k<3;++k){
                ret.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod;
                ret.a[i][j]%=mod;
            }
        }
    return ret;
}
matrix ksm(matrix x,ll k){
    matrix ret;
    memset(ret.a,0,sizeof(ret.a));
    ret.a[0][0]=ret.a[1][1]=ret.a[2][2]=1;
    if(k==0) return ret;
    if(k==1) return x;
    if(k%2==0) {
        ret=ksm(x,k/2);
        return muliti(ret,ret);
    }else{
        ret=ksm(x,k-1);
        return muliti(ret,x);
    }
}
思路:

数非常非常大,大到存不下,但是给你了末尾,就能推出来。

设该数为Sn。 Sn=Sn-1*10^k+n-1;

很明显构造3*3的矩阵, 

sn n -1

0   0  0

   0   0  0

然后构造10^k矩阵。

因为k有18种,所以构造18种情况,

10^k 0 0

1 1 0

1 1 1 

然后快速幂就行了。


#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int mod=11;
struct matrix{
    int a[3][3];
}C[20],ans;
ll n,nn;
void init(){
    ans.a[0][0]=ans.a[1][1]=ans.a[2][2]=1;
    C[1].a[0][0]=10;
    C[1].a[1][0]=C[1].a[2][0]=C[1].a[1][1]=C[1].a[2][1]=C[1].a[2][2]=1;
    for(int i=2;i<20;++i){
        C[i]=C[i-1];
        C[i].a[0][0]*=10;
        C[i].a[0][0]%=mod;
    }
}
matrix muliti(matrix x,matrix y){
    matrix ret;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j){
            ret.a[i][j]=0;
            for(int k=0;k<3;++k){
                ret.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod;
                ret.a[i][j]%=mod;
            }
        }
    return ret;
}
matrix ksm(matrix x,ll k){
    matrix ret;
    memset(ret.a,0,sizeof(ret.a));
    ret.a[0][0]=ret.a[1][1]=ret.a[2][2]=1;
    if(k==0) return ret;
    if(k==1) return x;
    if(k%2==0) {
        ret=ksm(x,k/2);
        return muliti(ret,ret);
    }else{
        ret=ksm(x,k-1);
        return muliti(ret,x);
    }
}
int main(){
    while(~scanf("%lld",&n)){
       memset(ans.a,0,sizeof(ans.a));
       nn=n;
       int len=0;
       while(nn){
         nn/=10;
         len++;
       }
       init();
       ll k=1;
       for(int i=1;i<len;++i){
          ans=muliti(ans,ksm(C[i],k*9));
          k*=10;
       }
       ans=muliti(ans,ksm(C[len],n-k+1));
       printf("%d\n",ans.a[2][0]);
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值