2017 武大校赛 I: A simple math problem(矩阵快速幂)

来源:互联网 发布:在线室内设计软件 编辑:程序博客网 时间:2024/06/05 14:35

问题 I: A simple math problem

时间限制: 1 Sec  内存限制: 512 MB
提交: 21  解决: 8
[提交][状态][讨论版]

题目描述

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 

样例输入

12021

样例输出

154

提示

1 ≡ 1( mod 11) 

1234567891011121314151617181920 ≡ 5( mod 11) 

123456789101112131415161718192021 ≡ 4( mod 11)

分析:F【i】是求1234....i %11的结果。

可得出:F【i】=(F【i-1】* i的位数+i)%11

矩阵A的构造:  

       F(i)【  i的位数,1 ,1 】 F(i-1)

        i        【       0     ,1 ,1 】 i-1

       1        【       0     ,0 , 1】 1


因为i 的位数最多有18个,所以分成18个矩阵加速来写。

附提交网站

代码:

#include <iostream>  #include <cstdio>  #include <cstring>  #include <algorithm>  using namespace std;  long long N,MOD;  struct Mat{      long long A[3][3];  }S[20],ans;  Mat operator * (Mat a,Mat b)  {      Mat ret;      ret.A[0][0]=(a.A[0][0]*b.A[0][0]+a.A[0][1]*b.A[1][0]+a.A[0][2]*b.A[2][0])%MOD;      ret.A[0][1]=(a.A[0][0]*b.A[0][1]+a.A[0][1]*b.A[1][1]+a.A[0][2]*b.A[2][1])%MOD;      ret.A[0][2]=(a.A[0][0]*b.A[0][2]+a.A[0][1]*b.A[1][2]+a.A[0][2]*b.A[2][2])%MOD;        ret.A[1][0]=(a.A[1][0]*b.A[0][0]+a.A[1][1]*b.A[1][0]+a.A[1][2]*b.A[2][0])%MOD;      ret.A[1][1]=(a.A[1][0]*b.A[0][1]+a.A[1][1]*b.A[1][1]+a.A[1][2]*b.A[2][1])%MOD;      ret.A[1][2]=(a.A[1][0]*b.A[0][2]+a.A[1][1]*b.A[1][2]+a.A[1][2]*b.A[2][2])%MOD;        ret.A[2][0]=(a.A[2][0]*b.A[0][0]+a.A[2][1]*b.A[1][0]+a.A[2][2]*b.A[2][0])%MOD;      ret.A[2][1]=(a.A[2][0]*b.A[0][1]+a.A[2][1]*b.A[1][1]+a.A[2][2]*b.A[2][1])%MOD;      ret.A[2][2]=(a.A[2][0]*b.A[0][2]+a.A[2][1]*b.A[1][2]+a.A[2][2]*b.A[2][2])%MOD;      return ret;  }             void init()  {      S[1].A[0][0]=10%MOD;      S[1].A[1][0]=1;      S[1].A[1][1]=1;      S[1].A[2][0]=1;      S[1].A[2][1]=1;      S[1].A[2][2]=1;      ans.A[0][0]=1;      ans.A[1][1]=1;      ans.A[2][2]=1;      for (int i=2;i<20;i++)      {          S[i]=S[i-1];          S[i].A[0][0]*=10;          S[i].A[0][0]%=MOD;      }  }  Mat Ksm(Mat a,long long k)  {      Mat ret;      ret.A[0][0]=ret.A[1][1]=ret.A[2][2]=1;      if (k==0)          return ret;      if (k==1)          return a;      if (k%2==0)      {          ret=Ksm(a,k/2);          return ret*ret;      }else      {          ret=Ksm(a,k-1);          return ret*a;      }  }  int main()  {      long long begin=1,i,nn,len=0,k=1;      MOD = 11;      scanf("%lld",&N);      init();      nn=N;            while (nn)      {          nn/=10;          len++;      }            for (i=1;i<len;i++)      {          //每9个计算一次,因为如果进位了,k值就发生了变化,就要乘变化后的矩阵了,大牛不愧是大牛          ans=ans*Ksm(S[i],k*9);          k*=10;      }      //每次k都是*10,但实际计算的是*9的和,比如我算到9999,此时的k值为10000,所以此处需要+1      //由于减后剩下的值都不会进位,所以直接乘最大位数的转置矩阵即可      ans=ans*Ksm(S[len],N-k+1);      printf("%lld\n",ans.A[2][0]);      return 0;  }  


0 0
原创粉丝点击