您的位置:首页 > 其它

[BZOJ]4547: Hdu5171 小奇的集合 矩阵乘法

2017-04-15 11:42 288 查看

Description

 有一个大小为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取模。

一看就是矩阵乘法啦……注意一下一开始的最大有负数的情况以及众多细节就好了……

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const LL mod=10000007;
const LL inf=2147483647;
LL n,a[100005],k;
struct matrix{LL m[3][3],l,r;}u,ans,o;
matrix cheng(matrix x,matrix y)
{
ans.l=y.l;ans.r=x.r;
memset(ans.m,0,sizeof(ans.m));
for(LL i=0;i<=ans.l;i++)
for(LL j=0;j<=ans.r;j++)
for(LL k=0;k<=x.l;k++)
{
ans.m[i][j]+=x.m[k][j]*y.m[i][k];
ans.m[i][j]=(ans.m[i][j]+mod)%mod;
}
}
void work(matrix b,LL k)
{
if(k==1) o=b;
else
{
work(b,k/2);
cheng(o,o);o=ans;
if(k%2==1)
{
cheng(b,o);
o=ans;
}
}
}
int main()
{
LL m1=-inf,m2=-inf,sum=0;
scanf("%lld%lld",&n,&k);
for(LL i=1;i<=n;i++)
{
scanf("%lld",&a[i]);a[i]%=mod;
sum+=a[i];sum%=mod;
}
sort(a+1,a+1+n);
m1=a
;m2=a[n-1];
if(m2<0)
{
while(1)
{
sum=sum+m2+m1;
sum=(sum+mod)%mod;
m2+=m1;
k--;
if(m2>=0) break;
}
}
if(k==0) {printf("%lld",sum);return 0;}
u.l=u.r=2;
u.m[0][0]=0;u.m[0][1]=1;u.m[0][2]=0;
u.m[1][0]=1;u.m[1][1]=1;u.m[1][2]=0;
u.m[2][0]=1;u.m[2][1]=1;u.m[2][2]=1;
matrix v;
v.l=2;v.r=0;
v.m[0][0]=m2;v.m[1][0]=m1;v.m[2][0]=sum;
work(u,k);
cheng(v,o);
printf("%lld",ans.m[2][0]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: