卧薪尝胆,厚积薄发。
HNOI2011 数学作业
Date: Fri Sep 07 08:27:22 CST 2018
In Category:
NoCategory
Description:
计算
$1,2,\dots,N$
顺序连接起来的数
$\%m$
的值。
$1\le n \le 10^{18}$
Solution:
$10^{18}$
的数据范围差不多就是矩阵快速幂了,转移方程为
$f[i]=f[i-1]\times 10^{\lfloor\lg i\rfloor}+i(\text{mod }m)$
,枚举
$\lfloor \lg i\rfloor$
构造矩阵即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
ll n,p;
struct matrix
{
ll m[4][4];
matrix(){memset(m,0,sizeof(m));}
friend matrix operator * (matrix a,matrix b)
{
matrix c;
for(int i = 1;i <= 3;++i)
for(int j = 1;j <= 3;++j)
for(int k = 1;k <= 3;++k)
c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j] % p) % p;
return c;
}
friend matrix operator ^ (matrix a,ll b)
{
matrix res = a;--b;
while(b > 0)
{
if(b & 1)res = res * a;
a = a * a;
b = b >> 1;
}
return res;
}
}f,res;
int main()
{
scanf("%lld%lld",&n,&p);
res.m[1][1] = res.m[1][2] = res.m[1][3] = 1;
f.m[1][1] = 10;
f.m[2][1] = f.m[3][1] = f.m[2][2] = f.m[3][2] = f.m[3][3] = 1;
if(n <= 9)
{
for(int b = 2;b <= n;++b)
{
res = res * f;
}
cout << res.m[1][1] << endl;
return 0;
}
else res = res * (f ^ 8);
for(ll b = 2,cur = 100;b <= 18;++b,cur *= 10)
{
f.m[1][1] = cur % p;
f.m[2][1] = f.m[3][1] = f.m[2][2] = f.m[3][2] = f.m[3][3] = 1;
if(n < cur)
{
res = res * (f ^ (n - cur / 10 + 1));
break;
}
else
{
res = res * (f ^ (cur / 10 * 9));
}
}
cout << res.m[1][1] << endl;
return 0;
}
In tag:
DP-矩阵加速
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡