HDU4686---Arc of Dream(矩阵快速幂,大数据的坑题)

来源:互联网 发布:java毕业设计免费下载 编辑:程序博客网 时间:2024/05/21 10:50

【题目来源】: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 longusing 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));    }}
原创粉丝点击