【题目来源】:https://vjudge.net/problem/HDU-4686
【题意】
题意如题面所述。AD(i)=AD(i-1)+ai*bi。
【思路】
很明显,矩阵快速幂,但是这道题相当坑。
第一:若是没有n==0的情况会给出超时的结果。(我还一直在想log
的复杂度怎么会超时)
第二:乘法中间的过程必须各种取余,否则会爆longlong。
好了,步入正题:
很多博客直接给出了现成的矩阵式子或者图形,新手估计看的一脸懵逼,那么我就给出一下我的推导过程吧。
首先呢,找出总的关系式:
AD(i)=AD(i-1)+a(i)*b(i)。
然后把右边所有i换成i-1,因为矩阵是这么个意思:前一项乘以系数矩阵得到下一项,也就是第i-1项乘以系数矩阵得到第i项,所以两边的元素要分清。
AD(i)=AD(i-1)+(a(i-1)*ax+ay)(b(i-1)*bx+by)
化简得:
AD(i)=AD(i-1)+ax*bx*a(i-1)*b(i-1)+ax*by*a(i-1)+ay*bx*b(i-1)+ay*by;
这个时候呢,递推式就出来了,那么接下来写出系数矩阵:
(的第一行,,嘿嘿)由等号右边的式子可得系数:
1 ax*bx ax*by ay*bx ayby
上面呢系数矩阵的第一行,那么该怎么推以下几行呢?(继续看)
刚才已经说过,是第i-1项乘以系数矩阵得到第i项,那么每个式子都会的到下一项:(以下是初始矩阵(也就是右边除了系数之外的))
初始矩阵(坐标)当前项————>下一项(矩阵坐标)
AD(i-1)(1,1)—————–>AD(i)(1,1)
a[i-1]*b[i-1](2,1)————>a[i]*b[i](2,1)
a[i-1](3,1)——————->a[i](3,1)
b[i-1](4,1)——————->b[i](4,1)
1(5,1)———————–>1(5,1)
由于矩阵乘法可知:
AD(i)的坐标是(1,1),那么就等于系数矩阵的第一行乘以初始矩阵的第一列;
a[i]*b[i]的坐标是(2,1),那么就等于系数矩阵的第二行乘以初始矩阵的第二列;(以此来推出系数矩阵的第二行)
。。。
。。。
。。。
( 这也是一般系数矩阵的推理方法)
然后推出的系数矩阵是这样的:
然后这道题就可以做了。。。
【代码】
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const LL mod=1e9+7;
LL a0,ax,ay;
LL b0,bx,by;
struct mat
{
LL a[6][6];
};
mat operator*(mat &s,mat &t)
{
mat r;
memset(r.a,0,sizeof(r.a));
for(int i=1; i<=5; i++)
{
for(int j=1; j<=5; j++)
{
for(int k=1; k<=5; k++)
{
r.a[i][j]+=(s.a[i][k]*t.a[k][j])%mod;
r.a[i][j]%=mod;
}
}
}
return r;
}
LL pow_mat(mat base,LL k)
{
mat ans;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
ans.a[i][j]=(i==j);
while(k)
{
if(k&1)
{
ans=ans*base;
}
base=base*base;
k>>=1;
}
return (ans.a[1][1]*a0%mod*b0%mod+ans.a[1][2]*a0%mod*b0%mod+ans.a[1][3]*a0%mod+ans.a[1][4]*b0%mod+ans.a[1][5]%mod)%mod;//相当于初始矩阵与系数矩阵的乘法
}
int main()
{
LL n;
while(~scanf("%lld",&n))
{
scanf("%lld%lld%lld",&a0,&ax,&ay);
scanf("%lld%lld%lld",&b0,&bx,&by);
mat base;
memset(base.a,0,sizeof(base.a));
base.a[1][1]=1;
base.a[1][2]=ax*bx%mod;
base.a[1][3]=ax*by%mod;
base.a[1][4]=ay*bx%mod;
base.a[1][5]=ay*by%mod;
base.a[2][2]=ax*bx%mod;
base.a[2][3]=ax*by%mod;
base.a[2][4]=ay*bx%mod;
base.a[2][5]=ay*by%mod;
base.a[3][3]=ax;
base.a[3][5]=ay;
base.a[4][4]=bx;
base.a[4][5]=by;
base.a[5][5]=1;
if(n==0)
{
printf("0\n");
continue;
}
printf("%lld\n",pow_mat(base,n-1));
}
}