题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=2326
思路
感觉自己真的是弱到不能自理。。。这道比较基础的矩阵题居然做了大半天。。。
首先还是考虑DP怎么做这个题。。。。
假设
f[i]=Concatenate(1...i)
,很容易得到下面的递推方程
f[i]=f[i−1]∗(|i|+1)+i
然后可以用一个矩阵进行优化
⎡⎣⎢fn+1n+11⎤⎦⎥=⎡⎣⎢10k00110111⎤⎦⎥⎡⎣⎢fnn1⎤⎦⎥
对于长度相同( 10k 相同)的数字段(0~9、10~99……)而言,我们对这些段一段一段地进行矩阵快速幂即可。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 1000
using namespace std;
typedef long long int LL;
LL MOD;
struct Matrix
{
LL num[5][5];
int n,m;
Matrix()
{
n=m=0;
memset(num,0,sizeof(num));
}
}a,one,x;
Matrix operator*(Matrix a,Matrix b)
{
Matrix c;
c.n=a.n,c.m=b.m;
for(int k=1;k<=a.m;k++)
for(int i=1;i<=c.n;i++)
for(int j=1;j<=c.m;j++)
c.num[i][j]=(c.num[i][j]+(a.num[i][k]%MOD)*(b.num[k][j]%MOD)%MOD)%MOD;
return c;
}
Matrix fastPow(Matrix base,LL pow)
{
Matrix ans=one;
while(pow)
{
if(pow&1) ans=ans*base;
base=base*base;
pow>>=1;
}
return ans;
}
int main()
{
LL n;
scanf("%lld%lld",&n,&MOD);
//MOD=1e18;
one.n=one.m=3;
for(int i=1;i<=3;i++) one.num[i][i]=1;
a=one;
a.num[1][1]=10,a.num[1][2]=a.num[1][3]=a.num[2][2]=a.num[2][3]=a.num[3][3]=1;
a.num[2][1]=a.num[3][1]=a.num[3][2]=0;
x.n=3,x.m=1;
x.num[1][1]=0,x.num[2][1]=0,x.num[3][1]=1;
LL t=10;
while(t<=n)
{
a=fastPow(a,t-t/10);
x=a*x;
a=one;
a.num[1][1]=t*10%MOD,a.num[1][2]=a.num[1][3]=a.num[2][2]=a.num[2][3]=a.num[3][3]=1;
a.num[2][1]=a.num[3][1]=a.num[3][2]=0;
t*=10;
}
a=one;
a.num[1][1]=t%MOD,a.num[1][2]=a.num[1][3]=a.num[2][2]=a.num[2][3]=a.num[3][3]=1;
a.num[2][1]=a.num[3][1]=a.num[3][2]=0;
a=fastPow(a,n-t/10+1);
x=a*x;
printf("%lld\n",x.num[1][1]);
return 0;
}