您的位置:首页 > 其它

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

2016-05-17 10:20 323 查看
 有一个大小为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,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
+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
;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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: