hdu 5171-GTY's birthday gift(矩阵快速幂)

来源:互联网 发布:淘宝开店实名认证怎么弄 编辑:程序博客网 时间:2024/05/02 03:01

题目及代码:题目大意就是给定一个含有n个元素的序列,进行k次操作---每次操作从序列里面选择两个数,求和并将结果放在这个序列中,使得k次操作后这个序列中的元素和最大。

    当然为了满足最大这个要求,那么我们每次当然是从序列中选择最大的两个元素相加,结果放在这个序列中,这个结果比为序列元素的最大元素。这样我们只需要找到原序列中最大的两个元素,累加就可以了。简单化简一下就知道这是一个经典的菲波那切数列求和,由于k很大,使用矩阵来加速就可以了,注意一下细节的处理,具体见代码:


#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;typedef long long ll;const ll mod=10000007;struct mat{    ll t[4][4];    void set()    {        memset(t,0,sizeof(t));    }}a,b;mat multiple(mat a,mat b,ll n,ll p){    ll i,j,k;    mat temp;    temp.set();    for(i=0; i<n; i++)        for(j=0; j<n; j++)        {            if(a.t[i][j]!=0)                for(k=0; k<n; k++)                    temp.t[i][k]=(temp.t[i][k]+a.t[i][j]*b.t[j][k])%p;        }    return temp;}mat quick_mod(mat b,ll n,ll m,ll p){    mat t;    t.set();    for(ll i=0; i<n; i++) t.t[i][i]=1;    while(m)    {        if(m&1)        {            t=multiple(t,b,n,p);        }        m>>=1;        b=multiple(b,b,n,p);    }    return t;}void init(){    b.set();    b.t[0][1]=b.t[0][2]=1;    b.t[1][0]=b.t[1][1]=1;    b.t[1][2]=b.t[2][2]=1;}int main(){    ll n,k;    while(scanf("%I64d%I64d",&n,&k)!=EOF)    {        ll sum=0,x=0,y=0,z=0,A=0,B=0;        for(int i=0;i<n;i++)        {            scanf("%I64d",&x);            sum=(sum+x)%mod;            if(x>B) B=x;            if(A<B) swap(A,B);        }        if(k==1)        {            sum=(sum+A+B)%mod;            printf("%I64d\n",sum);            continue;        }        if(k==2)        {            sum=(sum+A*3+B*2)%mod;            printf("%I64d\n",sum);            continue;        }        init();        a=quick_mod(b,3,k-2,mod);        z=a.t[0][2]+a.t[1][2]+2*a.t[2][2];        sum=(sum+(z%mod)*(B%mod)%mod)%mod;        z=a.t[0][2]+2*a.t[1][2]+3*a.t[2][2];        sum=(sum+(z%mod)*(A%mod)%mod)%mod;        printf("%I64d\n",sum);    }    return 0;}



0 0