BZOJ2326 [HNOI2011]数学作业 【矩阵快速幂】

题解##

我们设f[i]表示前i个数模M意义下的答案
则f[i] = f[i - 1] * 100...0 + i【i是几位就有几个0】
可以写出矩阵递推式:

之后按位数分组矩乘就好了

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s) memset(s,0,sizeof(s))
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
LL N,M;
struct Matrix{
	LL s[3][3],n,m;
	Matrix(){cls(s); n = m = 0;}
}A,F;
Matrix operator *(const Matrix& a,const Matrix& b){
	Matrix ans;
	if (a.m !=b.n) return ans;
	ans.n = a.n; ans.m = b.m;
	for (int i = 0; i < ans.n; i++)
		for (int j = 0; j < ans.m; j++)
			for (int k = 0; k < a.m; k++)
				ans.s[i][j] = (ans.s[i][j] + a.s[i][k] * b.s[k][j] % M) % M;
	return ans;
}
Matrix qpow(Matrix a,LL b){
	Matrix ans; ans.n = ans.m = a.n;
	for (int i = 0; i < ans.n; i++) ans.s[i][i] = 1;
	for (; b; b >>= 1,a = a * a)
		if (b & 1) ans = ans * a;
	return ans;
}
int S[][3] = {
	{1,1,1},
	{0,1,1},
	{0,0,1}
};
int main(){
	cin >> N >> M;
	A.n = A.m = 3;
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++)
			A.s[i][j] = S[i][j];
	F.n = 3; F.m = 1;
	F.s[0][0] = 0; F.s[1][0] = 0; F.s[2][0] = 1;
	for (LL bit = 1; ; bit *= 10){
		A.s[0][0] = bit % M * 10 % M;
		if (N < bit * 10){
			F = qpow(A,N - bit + 1) * F;
			break;
		}else F = qpow(A,bit * 10 - bit) * F;
	}
	cout << F.s[0][0] << endl;
	return 0;
}

posted @ 2018-02-02 13:19  Mychael  阅读(181)  评论(0编辑  收藏  举报