[HNOI2011]数学作业
题目描述
小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:
给定正整数 N 和 M,要求计算 Concatenate (1 .. N) Mod M 的值,其中 Concatenate (1 ..N)是将所有正整数 1, 2, …, N 顺序连接起来得到的数。例如,N = 13, Concatenate (1 .. N)=12345678910111213.小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。
输入输出格式
输入格式:
从文件input.txt中读入数据,输入文件只有一行且为用空格隔开的两个正整数N和M,其中30%的数据满足1≤N≤1000000;100%的数据满足1≤N≤1018且1≤M≤109.
输出格式:
输出文件 output.txt 仅包含一个非负整数,表示 Concatenate (1 .. N) Mod M 的值。
输入输出样例
输入样例#1:
13 13
输出样例#1:
4
题解:
题解:
这道题如果不是要考虑每一次乘上的数是10的几次方的话,那便是裸的矩阵快速幂,但是加上的话也无非就是多分几种情况讨论罢了。
首先看递推式:f[i]=f[i-1]*10^k+i(可以看出只要对k讨论)
然后写出两个矩阵:{{0,1,1},{0,0,0},{0,0,0}}和{{k%m,0,0},{1,1,0},{0,1,1}};
快速幂即可。
代码如下:(注意每次循环的分类讨论)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #include<stack> #include<ctime> #include<vector> using namespace std; typedef long long lol; lol n,m,now,pre; struct matrix { lol a[3][3]; matrix(){for(int i=0;i<3;i++)for(int j=0;j<3;j++)a[i][j]=0;} matrix(lol b[3][3]){for(int i=0;i<3;i++)for(int j=0;j<3;j++)a[i][j]=b[i][j];} friend matrix operator * (const matrix a,const matrix b) { matrix ans; for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) ans.a[i][j]=(ans.a[i][j]+(a.a[i][k]%m)*(b.a[k][j]%m)%m)%m; return ans; } }S,T; lol gi() { lol ans=0,f=1; char i=getchar(); while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} return ans*f; } int main() { lol i,j,k; n=gi();m=gi(); lol s[3][3]={{0,1,1},{0,0,0},{0,0,0}}; S=matrix(s); for(k=10;now<n;k*=10) { lol t[3][3]={{k%m,0,0},{1,1,0},{0,1,1}}; T=matrix(t); pre=min(k-1,n)-now; while(pre) { if(pre&1)S=S*T; T=T*T; pre>>=1; } now=min(k-1,n); } printf("%lld\n",S.a[0][0]); return 0; }