题目描述
小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:
给定正整数 和 ,要求计算 的值,其中 是将所有正整数 顺序连接起来得到的数。例如, , .小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。
输入输出格式
输入格式:
从文件input.txt中读入数据,输入文件只有一行且为用空格隔开的两个正整数N和M,其中30%的数据满足 ;100%的数据满足 且 .
输出格式:
输出文件 output.txt 仅包含一个非负整数,表示 的值。
输入输出样例
输入样例#1:
13 13
输出样例#1:
4
思路:根据题意易得递推式为(k为n的位数),直接构造矩阵是不可行的,因为矩阵中不存在这种变量。考虑按位数构造矩阵,那这时候就可以看作一个常数,注意不同位数的矩阵之间的衔接就没问题了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<climits>
using namespace std;
#define M(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef long long LL;
const int maxn = 100000+5;
struct Matrix {
LL mat[3][3];
};
LL n,mod;
Matrix operator * (Matrix a,Matrix b) {
Matrix res;
for (int i=0;i<3;++i) {
for (int j=0;j<3;++j) {
res.mat[i][j]=0;
for (int k=0;k<3;++k) {
res.mat[i][j]=res.mat[i][j]+a.mat[i][k]*b.mat[k][j];
res.mat[i][j]%=mod;
}
}
}
return res;
}
Matrix operator ^ (Matrix a,LL p) {
Matrix res;
M(res.mat,0);
for (int i=0;i<3;++i) {
res.mat[i][i]=1;
}
while(p) {
if (p&1) {
res=res*a;
}
a=a*a;
p>>=1;
}
return res;
}
LL f[20];
int main() {
scanf("%lld%lld",&n,&mod);
Matrix A,ans;
ans.mat[0][0]=0; ans.mat[0][1]=0;ans.mat[0][2]=0;
ans.mat[1][0]=1;ans.mat[1][1]=0;ans.mat[1][2]=0;
ans.mat[2][0]=1; ans.mat[2][1]=0;ans.mat[2][2]=0;
A.mat[0][0]=10; A.mat[0][1]=1;A.mat[0][2]=0;
A.mat[1][0]=0; A.mat[1][1]=1;A.mat[1][2]=1;
A.mat[2][0]=0; A.mat[2][1]=0;A.mat[2][2]=1;
int k = 0;
LL tp=n;
while(tp) {
tp/=10;
++k;
}
f[0]=1;
for (int i=1;i<=k;++i) {
f[i]=(f[i-1]<<3)+(f[i-1]<<1);
}
for (int i=1;i<=k;++i) {
A.mat[0][0]=f[i]%mod;
LL cnt;
if (i==k) {
cnt = n - f[i-1] + 1;
}
else {
cnt = f[i] - f[i-1];
}
ans=(A^cnt)*ans;
}
printf("%lld\n",ans.mat[0][0]);
return 0;
}