654. A simple math problem

Time Limit: 1000 ms / Mem. Limit: 524288 KiB / IO: ​​stdio​



Given a number WOJ 654 递推+矩阵快速幂_矩阵快速幂, you should calculate WOJ 654 递推+矩阵快速幂_递推_02 module 11

Input

A single line with an integer WOJ 654 递推+矩阵快速幂_矩阵快速幂 (WOJ 654 递推+矩阵快速幂_递推_04)

Output

Output one integer, WOJ 654 递推+矩阵快速幂_递推_02 module 11

Examples

Input 1

1

Output 1

1

Input 2

20

Output 2

5

Input 3

21

Output 3

4

Note

WOJ 654 递推+矩阵快速幂_矩阵快速幂_06

WOJ 654 递推+矩阵快速幂_#include_07

WOJ 654 递推+矩阵快速幂_#include_08.

Source

第六届华中区程序设计邀请赛暨武汉大学第十五届校赛




         此题就是之前所说的,矩阵快速幂递推啦。我就真的很好奇,为什么当时想不到用矩阵快速幂……


        题目,很容易理解,输入一个n,把从1开始到n的所有数字连成一个数字,然后问这个数字模11的结果是什么。

        首先,显然会想到n的结果就是n-1的结果乘上n的位数加上n再模11。O(n)的算法,但是仍然会超时。于是我就开始了漫长的找规律之旅,然后发现这是个无底洞……自己手残经常敲错东西,然后有时又忘了改一些东西。然后中午没有吃东西,脑子一片混乱,总之耗了一个多小时还没有弄出来。不,是WA了两次,然后放弃了。

        现在想来,把我的思想总结一下就是f(n)=(f(n-1)*10^p+n)%11。其中p表示n的位数。我想,如果我把这个式子写出来或许我就可以想到矩阵快速幂了,然而……那么我们就来说说矩阵对递推的式的优化吧。对于任何线性的递推,我们都可以把递推关系写在矩阵里面,即可以把通项公式写成an=a0*matrix^n,这样子的话,我们就可以利用矩阵乘法优化这个递推的过程。

        这题的话由于p的不同,所以我们要分成18个矩阵并分成一段一段地区求。构造方式的话设递推矩阵为x,x={{10^p,0,0}{1,1,0}{1,1,1}},然后的话首项是an={{an,n,1}{0,0,0}{0,0,0}},这样子刚好就可以完成递推,不信自己去试一试。关于构造这个矩阵,我记得我高中高OI的时候好像读过一篇文章专门讲如果构造递推矩阵,然而现在不记得了……下次找到了再讲吧。

  还有,值得注意到是,对于求位数p,本想装个B用log换底直接求位数,但是由于一些精度问题老师错……最后还是妥协了……代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iomanip>
#define ULL unsigned long long
#define mod 11
#define N 4
using namespace std;

struct matrix
{
ULL a[N][N];
} x,s,basic;

ULL n,y;

matrix matmulti(matrix x,matrix y)
{
matrix ans;
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
{
ans.a[i][j]=0;
for(int k=1;k<N;k++)
{
ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod;
ans.a[i][j]%=mod;
}
}
return ans;
}

matrix matpow(matrix x,ULL y)
{
if (y==0) return basic;
else
while ((y&1)==0)
{
y>>=1;
x=matmulti(x,x);
}
matrix ans=x;

y>>=1;
while (y!=0)
{
x=matmulti(x,x);
if ((y&1)!=0) ans=matmulti(ans,x);
y>>=1;
}
return ans;
}

int main()
{
s.a[1][1]=0;
x.a[2][1]=x.a[2][2]=1;
s.a[1][2]=0;s.a[1][3]=1;
x.a[3][1]=x.a[3][2]=x.a[3][3]=1;
for(int i=1;i<=3;i++) basic.a[i][i]=1;
scanf("%lld",&n);
ULL nn=n,p=0;
while (nn>0)
{
nn/=10; p++;
}
ULL i=10,j;
for(i=10,j=1;j<p;i*=10,j++)
{
x.a[1][1]=i%mod;
s=matmulti(s,matpow(x,9*i/10));
}
x.a[1][1]=i%mod;
s=matmulti(s,matpow(x,n-i/10+1));
printf("%lld",s.a[1][1]);
}