bzoj2326 矩阵乘法

http://www.lydsy.com/JudgeOnline/problem.php?id=2326

递推:f[i]= f[i-1]*(10^log(i))+i  mod M

构造矩阵:

{f[i-1] i-1  1}      {10^log(i)   0      0     }         { f[i]  i  1}
                   *   {1            1      0     }
                       { 0           1      1     }


也是:

| 10^log(i) 1      1 |             {f[i-1]}              {f[i]}               
| 0          1       1 |              { i-1}               { i }
| 0          0       1 |               { 1}                {1}


然后,初始化一下,对于每个数位做一次矩阵乘法,把结果乘起来。

(结果不会爆long long ,没有必要用乘法优化)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=5;
ll n,m;
struct Mat
{
	ll mat[maxn][maxn];
	Mat()
	{
		memset(mat,0,sizeof(mat));
	}
	Mat operator *(const Mat &b)
	{
		Mat c;
		for(int k=1;k<=3;k++)
		{
			for(int i=1;i<=3;i++)
			{
				for(int j=1;j<=3;j++)
				{
					c.mat[i][j]+=mat[i][k]*b.mat[k][j];
					c.mat[i][j]%=m;
				}
			}
		}
		return c;
	}
	
};
//f[i]= f[i-1]*(10^log(i))+i  mod M
/*
    f[i-1] i-1  1   10^log(i)   0      0   f[i]  i  1
                    1         1      0
                    0         1      1
                    
                    
10^log(i) 1      1              f[i-1]               
0         1      1                i-1
0         0      1                 1
*/
Mat ans;
Mat cal(ll k,ll t)
{
	Mat res;
	Mat b;
	ll y=t-k/10+1;
	b.mat[1][1]=k%m;
	b.mat[1][2]=b.mat[2][2]=b.mat[2][3]=b.mat[3][3]=b.mat[1][3]=1;
	for(int i=1;i<=3;i++)res.mat[i][i]=1;
	while(y)
	{
		if(y&1)res=res*b;
		y>>=1;
		b=b*b;
	}
	return res;
}
int main()
{
	//for(int i=1;i<=3;i++)ans.mat[i][i]=1;
	ans.mat[3][1]=1;
	scanf("%lld%lld",&n,&m);
	ll t=10;
	for(int i=1;i<=18;i++)
	{
		ans=cal(t,t-1)*ans;
		t*=10;
		if(t>n)break;
	}
	ans=cal(t,n)*ans;
	printf("%lld\n",ans.mat[1][1]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值