【bzoj 4547】【Hdu 5171】小奇的集合(找规律+矩阵快速幂)
4547: Hdu5171 小奇的集合
Time Limit: 2 Sec Memory Limit: 256 MB
Submit: 184 Solved: 90
[Submit][Status][Discuss]
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取模。
Sample Input
2 2
3 6
Sample Output
33
【题解】【找规律+矩阵快速幂】
【本题需要分两种情况考虑:1)序列的最大值和次大值都是非负整数;2)序列的次大值是负数】
【对于第二种情况,要先暴力地用最大值把次大值更新成非负整数并记录所需的次数t,若k
【若k
【由题意可知,设原序列为:
1)
2)
3)
……
【通过以上的列举,可以发现这是斐波那契数列,可以用矩阵乘法优化】
{1,0,0}
{1,1,1} * {
{0,1,0}
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=10000007;
struct unite{
ll k[3][3];
}d,f;
ll ans;
int n,m,h[100010],t;
int tmp(int a,int b)
{
return a>b;
}
inline unite jc(unite a,unite b)
{
int i,j,l;
unite c;
for(i=0;i<=2;++i)
for(j=0;j<=2;++j)
c.k[i][j]=0;
for(i=0;i<=2;++i)
for(j=0;j<=2;++j)
for(l=0;l<=2;++l)
c.k[i][j]=(c.k[i][j]+a.k[i][l]*b.k[l][j]%mod)%mod;
return c;
}
inline unite poww(unite d,int p)
{
unite sum;
for(int i=0;i<=2;++i)
for(int j=0;j<=2;++j)
sum.k[i][j]=0;
sum.k[0][0]=sum.k[1][1]=sum.k[2][2]=1;
for(;p;p>>=1,d=jc(d,d))
if(p&1)
sum=jc(sum,d);
return sum;
}
int main()
{
freopen("set.in","r",stdin);
freopen("set.out","w",stdout);
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) scanf("%d",&h[i]),ans+=h[i],ans%=mod;
if(!m) {printf("%I64d\n",ans); return 0;}
sort(h+1,h+n+1,tmp);
while(h[2]<0&&t<m) h[2]+=h[1],t++,ans+=h[2],ans%=mod;
if(t==m) {printf("%I64d\n",ans); return 0;}
d.k[0][0]=d.k[1][0]=d.k[1][1]=d.k[2][1]=d.k[1][2]=1;
d=poww(d,m-t-1);
f.k[0][0]=f.k[0][1]=f.k[0][2]=1;
f=jc(f,d);
ll t1=f.k[0][0],t2=(f.k[0][0]-1+f.k[0][1])%mod;
ans=(ans+(h[2]*t1%mod+h[1]*t2%mod)%mod)%mod;
ans=(ans+mod)%mod;
printf("%lld\n",ans);
return 0;
}