zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    十三周课程总结
    第十二周课程总结
    第十一周课程总结
    第十周java总结
    第九周课程总结&实验报告(七)
    第八周课程报告&&实验报告六
    第七次学习总结&&第五次实验报告
    第六次学习总结&&第四次实验总结
    同余&逆元简单总结
    原根&离散对数简单总结
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/5381858.html
Copyright © 2011-2022 走看看