问题 I: A simple math problem
时间限制: 1 Sec 内存限制: 512 MB提交: 8 解决: 3
[ 提交][ 状态][ 讨论版]
题目描述
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)
其实也想到了用矩阵快速幂写,但不会构建转置矩阵(看了大佬代码我明白了,即使求出转置矩阵,我也不一定能写出来)然后就废了,队友打表找规律一直找到最后也没找出来,GG,直接发上大佬的测试码,加点注释
转置矩阵(k表示位数)
10*k 0 0
1 1 0
1 1 1
每往末尾加一次数,就相当于乘一次转置矩阵,由于k会变,所以干脆直接构建出18个矩阵,对于不同位数的数乘上不同的转置矩阵,比如20,我就要乘上k=2的转置矩阵,200,乘上k=3的转置矩阵
#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;
}