hdu 5171 GTY's birthday gift

GTY's birthday gift

问题描述
 GTY的朋友ZZF的生日要来了,GTY问他的基友送什么礼物比较好,他的一个基友说送一个可重集吧!于是GTY找到了一个可重集S,GTY能使用神犇魔法k次,每次可以向可重集中加入一个数 a+b (a,bin S)a+b(a,bS),现在GTY想最大化可重集的和,这个工作就交给你了。
  注:可重集是指可以包含多个相同元素的集合
输入描述
多组数据(约3组),每组数据的第一行有两个数n,k(2 leq n leq 100000,1 leq k leq 1000000000)n,k(2n100000,1k1000000000) 表示初始元素数量和可使用的魔法数,第二行包含n个数a(1 leq a_i leq 100000)a(1ai​​100000)表示初始时可重集的元素
输出描述
对于每组数据,模10000007输出可重集可能的最大和。
输入样例
3 2
3 6 2
输出样例
35

这道题的解题思路很简单,用矩阵快速幂实现一个斐波那契数列求和(初值改变)
难点在于矩阵的构造,首先列出三个要维护的值
|   sum     |
|  a[n-1]  |
|  a[n-2]  |
那么可以想到这个矩阵的下一个形式必然为
| sum+a[n-1]+a[n-2] |
| a[n-1]+a[n-2]         |
| a[n-1]                     |
由此可以得到需要构造的友矩阵为
| 1 1 1 |
| 0 1 1 |
| 0 1 0 |
有了这个友矩阵,就可以进行矩阵快速幂了,先求
| 1 1 1 |
| 0 1 1 |  的K次方,然后再乘以初始矩阵就可以得到sum
| 0 1 0 |
 
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn=111;
const int Max=1e5+10;
const int MOD=10000007;
int a[Max];
struct matrix
{
    int w;
    LL m[maxn][maxn];        //注意矩阵也要用LL,不然会出现溢出
    matrix(int ww):w(ww){memset(m,0,sizeof(m));};
    matrix(){}
};
matrix operator * (matrix a,matrix b)
{
    matrix res(3);
    LL x;
    for(int i=0;i<res.w;i++)
    {
        for(int j=0;j<res.w;j++)
        {
            x=0;
            for(int k=0;k<res.w;k++)
            {
                x=(x+(LL)a.m[i][k]*b.m[k][j])%MOD;
            }
            res.m[i][j]=x;
        }
    }
    return res;
}
matrix fast_cover(int k)
{
    matrix base(3);
    base.m[0][0]=base.m[0][1]=base.m[0][2]=1;
    base.m[1][1]=base.m[1][2]=base.m[2][1]=1;
    base.m[1][0]=base.m[2][0]=base.m[2][2]=0;
    matrix s(3);
    s.m[0][0]=s.m[1][1]=s.m[2][2]=1;
    while(k)
    {
        if(k&1) s=s*base;
        base=base*base;
        k>>=1;
    }
    return s;
}
int main()
{
    int n,k;LL sum;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        sum=0;
        for(int i=0;i<n;i++)  scanf("%d",&a[i]),sum+=a[i];
        sort(a,a+n);
        matrix ss=fast_cover(k);
        LL ans=(ss.m[0][0]*sum+ss.m[0][1]*a[n-1]+ss.m[0][2]*a[n-2])%MOD;
        printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zsyacm666666/p/5381858.html