【bzoj4547】【小奇的集合】【矩阵乘法】

 有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大

值。(数据保证这个值为非负数)

Input

第一行有两个整数n,k表示初始元素数量和操作数,第二行包含n个整数表示初始时可重集的元素。

对于100%的数据,有 n<=10^5,k<=10^9,|ai|<=10^5

Output

输出一个整数,表示和的最大值。答案对10000007取模。

Sample Input

2 2
3 6

Sample Output

33
题解:
首先如果最大值和次大值都是正数肯定是这两个数向上累加.
如果最大值和次大值一正一负,那就先把负数加成正数.
之后的累加操作显然可以用矩阵乘法加速.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define P 10000007
#define N 100010
#define ll long long
using namespace std;
int v[N],n,k;
long long s;
struct use{
  ll a[5][5];
  use(){memset(a,0,sizeof(a));}
  friend use operator*(use a,use b){
    use c;
    for (int i=1;i<=3;i++)
      for (int j=1;j<=3;j++)
        for (int k=1;k<=3;k++)
          (c.a[i][j]+=(a.a[i][k]*b.a[k][j])%P)%=P;
    return c;
  }     
  friend use operator^(use a,int b){
    use ans;
    for (int i=1;i<=3;i++) ans.a[i][i]=1;
    for (int i=b;i;i>>=1,a=a*a) if (i&1) ans=ans*a;
    return ans;
  }
}a,ans;
int main(){
  scanf("%d%d",&n,&k);
  for (int i=1;i<=n;i++) scanf("%d",&v[i]),(s+=(ll)v[i])%=P;
  sort(v+1,v+n+1);
  while (v[n-1]<0&&k){
    v[n-1]=(v[n]+v[n-1])%P;
    (s+=(ll)v[n-1])%=P;k--;
  }
  a.a[1][1]=1;a.a[1][2]=1;a.a[1][3]=0;
  a.a[2][1]=1;a.a[2][2]=0;a.a[2][3]=0;
  a.a[3][1]=1;a.a[3][2]=1;a.a[3][3]=1;
  ans.a[1][1]=v[n];ans.a[2][1]=v[n-1];ans.a[3][1]=s;
  ans=(a^k)*ans;int x=(ans.a[3][1]+P)%P;
  printf("%d",x);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值