P3216 [HNOI2011]数学作业

题目

分析

首先容易写出方程是:\(dp[i]=dp[i-1]*10^{\lfloor lg(i) \rfloor+1}+i\)

然后我们发现这个\(*10^{\lfloor lg(i) \rfloor+1}\)并不好使用矩阵快速幂来优化。

但是这个值似乎很少,只在\([1,19]\)有取值。

于是考虑直接枚举这个值设为\(k\),那么方程就变成了 \(dp[i]=k\times dp[i-1]+i\)

这就是很容易转移的一个形式了,直接矩阵快速幂优化。

至于最后的答案就是就是把这些步骤全部拼起来即可,具体见代码。

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
ll n,m,MOD;
ll Pow[20];
struct Matrix{
	ll a[3][3];
	Matrix(){memset(a,0,sizeof(a));}
	inline Matrix operator * (const Matrix &B)const{
		Matrix C;
		for(int i=0;i<3;i++){
			for(int k=0;k<3;k++){
				int r=a[i][k];
				for(int j=0;j<3;j++) C.a[i][j]=(C.a[i][j]+r*B.a[k][j])%MOD;
			}
		}
		return C;
	}
};
struct Vector{
	ll a[3];
	Vector(){memset(a,0,sizeof(a));}
	friend inline Vector operator * (const Vector &A,const Matrix &B){
		Vector C;
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++) C.a[i]=(C.a[i]+A.a[j]*B.a[j][i])%MOD;
		}
		return C;
	}
};
inline Matrix QuickPow(Matrix x,ll y){
	Matrix res;
	for(int i=0;i<3;i++) res.a[i][i]=1;
	while(y){
		if(y&1) res=res*x;
		x=x*x;
		y>>=1;
	}
	return res;
}
signed main(){
	read(n),read(MOD);
	const int len=(int)floor(log(n)/log(10));
	Pow[0]=1;
	for(int i=1;i<=len+1;i++) Pow[i]=Pow[i-1]*10;
	Vector now;
	now.a[0]=0,now.a[1]=0,now.a[2]=1;
	for(int i=0;i<len;i++){
		Matrix trans;
		trans.a[0][0]=Pow[i+1]%MOD;
		trans.a[1][0]=trans.a[1][1]=trans.a[2][0]=trans.a[2][1]=trans.a[2][2]=1;
		trans=QuickPow(trans,(9*Pow[i]));
		now=now*trans;
	}
	Matrix trans;
	trans.a[0][0]=Pow[len+1]%MOD;
	trans.a[1][0]=trans.a[1][1]=trans.a[2][0]=trans.a[2][1]=trans.a[2][2]=1;
	now=now*QuickPow(trans,n-Pow[len]+1);
	write(now.a[0]);
	return 0;
}

感受

这样“直接枚举不太好维护且值域较小的量”的技巧值得学习,在很多地方都有用到,可以当成一个小\(trick\)

posted @ 2021-07-21 20:45  __Anchor  阅读(250)  评论(0)    收藏  举报