bzoj 2326: [HNOI2011]数学作业【dp+矩阵快速幂】

矩阵乘法一般不满足交换律!!所以快速幂里需要注意乘的顺序!!
其实不难,设f[i]为i的答案,那么f[i]=(f[i-1]*w[i]+i)%mod,w[i]是1e(i的位数),这个很容易写成矩阵的形式,然后按每一位分别矩阵快速幂即可
矩阵:
f[i-1] w[i] 1 1 f[i]
i-1 * 0 1 1 = i
1 0 0 1 1

#include<iostream>
#include<cstdio>
using namespace std;
long long n,mod,t;
long long mul(long long a,long long b)
{
	long long r=0;
	while(b)
	{
		if(b&1)
			r=(r+a)%mod;
		a=(a<<1)%mod;
		b>>=1;
	}
	return r;
}
struct qwe
{
	long long a[5][5];
	qwe operator * (const qwe &b) const
	{
		qwe c;
		for(int i=1;i<=3;i++)
			for(int j=1;j<=3;j++)
			{
				c.a[i][j]=0;
				for(int k=1;k<=3;k++)
					c.a[i][j]=(c.a[i][j]+mul(a[i][k],b.a[k][j]))%mod;
			}
		return c;
	}
}r;
void wk(long long t,long long la)
{
	long long b=la-t/10+1;//cerr<<b<<endl;
	qwe a;
	a.a[1][1]=t,a.a[1][2]=1,a.a[1][3]=1;
	a.a[2][1]=0,a.a[2][2]=1,a.a[2][3]=1;
	a.a[3][1]=0,a.a[3][2]=0,a.a[3][3]=1;
	while(b)
	{
		if(b&1)
			r=a*r;
		a=a*a;
		b>>=1;
	}
}
int main()
{
	scanf("%lld%lld",&n,&mod);
	r.a[1][1]=r.a[2][2]=r.a[3][3]=1;
	for(t=10;t<=n;)
		wk(t,t-1),t*=10ll;
	wk(t,n);
	printf("%lld\n",r.a[1][3]);
	return 0;
}
posted @ 2018-09-07 16:51  lokiii  阅读(100)  评论(0编辑  收藏  举报