P3216 [HNOI2011]数学作业 (矩阵快速幂)

P3216 [HNOI2011]数学作业

题目描述

小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:

给定正整数 NN 和 MM ,要求计算 Concatenate (1 .. N) Concatenate(1..N) ModMod MM 的值,其中 Concatenate (1 .. N) Concatenate(1..N) 是将所有正整数 1, 2, …, N1,2,…,N 顺序连接起来得到的数。例如, N = 13N=13 , Concatenate (1 .. N)=12345678910111213Concatenate(1..N)=12345678910111213 .小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。

输入输出格式

输入格式:
从文件input.txt中读入数据,输入文件只有一行且为用空格隔开的两个正整数N和M,其中30%的数据满足 1≤N≤10000001≤N≤1000000 ;100%的数据满足 1≤N≤10^{18}1≤N≤$ 10^18 ( 且 1≤M≤) 10^9 (1≤M≤1) 0^9 $
.
输出格式:
输出文件 output.txt 仅包含一个非负整数,表示 Concatenate (1 .. N)Concatenate(1..N) ModMod MM 的值。

输入输出样例

输入样例#1:
13 13
输出样例#1:
4

递推式容易得到:$$ f[i+1]=f[i]*10^{k}+i+1 $$
范围 $ n<=10^{18} $
线性算法肯定TLE,那就考虑log的算法(快速幂或者倍增)
考虑把递推式转换成矩阵
递推式有三项
经验告诉我们,也许要用到(3*3)的矩阵
经过一系列 碰数,凑数,计算
我们得到矩阵

[egin{pmatrix} f[n+1],n+1,1 end{pmatrix}= egin{pmatrix} f[n],n,1 end{pmatrix} imes egin{bmatrix} 10^{k},0,0\1,1,0\1,1,1 end{bmatrix} ]

从而可以得到

[egin{pmatrix} f[n+1],n+1,1 end{pmatrix}= =egin{pmatrix} f[1],1,1 end{pmatrix} imes egin{bmatrix} 10^{k},0,0\1,1,0\1,1,1end{bmatrix}^{n-1}]

ps:k是位数

k虽然是不确定的,但k的范围却很小 <=18
所以分开做就可以了

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
ll n,mod;
struct node {
	ll m[4][4];
} ans,ss,a;
node mul(node x,node y) {
	node 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]+(x.m[i][k]*y.m[k][j])%mod)%mod;
	return c;
}
void fpow(ll p) {
	while(p) {
		if(p&1)	ans=mul(ans,ss);
		ss=mul(ss,ss);
		p>>=1;
	}
}
int main() {
	//全部开long long不要质疑
	cin>>n>>mod;
	ans.m[1][3]=a.m[1][1]=a.m[2][1]=a.m[2][2]=a.m[3][1]=a.m[3][2]=a.m[3][3]=1;
	for(ll i=1,j; i<=n; i=j+1) {
		j=i*10-1;
		if(j>n) j=n;
		a.m[1][1]=a.m[1][1]*(ll)10%mod;
		ss=a;
		fpow(j-i+1);
	}
	printf("%lld
",ans.m[1][1]%mod);
	return 0;
}

自己还是太弱,最后处理菜的要死

原文地址:https://www.cnblogs.com/dsrdsr/p/9301009.html