数学作业
- Description
小C数学成绩优异,于是老师给小C留了一道非常难的数学作业题: 给定正整数 N和M,要求计算Concatenate(1..N)Mod M的值,其中Concatenate(1..N)是将所有正整数1,2,…,N顺序连接起来得到的数。例如,N=13, Concatenate(1..N)=12345678910111213.小C想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。
- Input Format
只有一行,为用空格隔开的两个正整数N和M。
- Output Format
仅包含一个非负整数,表示Concatenate(1..N)Mod M的值。
- Sample Input
【输入样例1】
13 13
【输入样例2】
12345678910 1000000000
- Sample Output
【输出样例1】
4
【输出样例2】
345678910
- Hint
30%的数据满足1≤ N ≤1000000
100%的数据满足1≤ N ≤10^18且1≤ M ≤10^9
- 分析
30%暴力,顺着题意模拟即可。
100%我们发现对于一段数位相等的数,每次操作就是把原数乘k(k位数)再加上一个k位数,这样我们可以构造一个矩阵快速乘,把时间降到log级别。然后分段(1~9、10~99……)处理。
一年前的代码
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <map>
using namespace std;
long long n,m,ans[4],i;
void mi(long long x10,long long times){
x10%=m;
long long a[4][4]={{0,0,0,0},{0,x10,0,0},{0,1,1,0},{0,1,1,1}};
long long b[4][4]={{0,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
long long s[4][4];
for (;times;times>>=1){
if (times%2==1){
for (long long i=1;i<=3;i++){
for (long long j=1;j<=3;j++){
s[i][j]=((b[i][1]%m*a[1][j]%m)%m+(b[i][2]%m*a[2][j]%m)%m+(b[i][3]%m*a[3][j]%m)%m)%m;
}
}
for (long long i=1;i<=3;i++){
for (long long j=1;j<=3;j++){
b[i][j]=s[i][j];
}
}
}
for (long long i=1;i<=3;i++){
for (long long j=1;j<=3;j++){
s[i][j]=((a[i][1]%m*a[1][j]%m)%m+(a[i][2]%m*a[2][j]%m)%m+(a[i][3]%m*a[3][j]%m)%m)%m;
}
}
for (long long i=1;i<=3;i++){
for (long long j=1;j<=3;j++){
a[i][j]=s[i][j];
}
}
}
s[1][1]=((ans[1]*b[1][1]%m)%m+(ans[2]%m*b[2][1]%m)%m+(ans[3]%m*b[3][1]%m)%m)%m;
s[2][1]=ans[1]*b[1][2]+ans[2]*a[2][2]+ans[3]*b[3][2];
s[3][1]=ans[1]*b[1][3]+ans[2]*a[2][3]+ans[3]*b[3][3];
ans[1]=s[1][1]; ans[2]=s[2][1]; ans[3]=s[3][1];
}
int main(){
freopen("homework.in","r",stdin);
freopen("homework.out","w",stdout);
scanf("%lld%lld",&n,&m);
ans[1]=ans[2]=0;ans[3]=1;
for (i=10;i<=n;i*=10){
mi(i,9*i/10);
}
mi(i,n-(i/10)+1);
printf("%d",ans[1]);
fclose(stdin); fclose(stdout);
}