BZOJ4547 Hdu5171 小奇的集合

题意

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

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

分析

参照GXZlegend的题解。

矩阵乘法

显然每次选择集合中最大的两个数相加即可。

如果最大的两个数都是正数,那么结果显然也是正数并且比它们都要大,即\((b,a)→(a,a+b)\),所以可以使用矩阵乘法来解决。

具体过程:
\[ \left[ \begin{matrix} a & b &s \end{matrix} \right] * \left[ \begin{matrix} 1 & 1& 1\\ 1 & 0& 0\\ 0 & 0& 1 \end{matrix} \right]= \left[ \begin{matrix} a+b & a &s+a \end{matrix} \right] \]
如果最大的两个数都是负数,那么结果显然也是负数并且比它们都要小,因此直接选择它们相加k次即可。

如果这两个数一正一负,那么每次负数会变大,由于数的范围只有\(10^5\),因此可以暴力操作直到加到正数或者没有操作机会,然后矩乘即可。

时间复杂度\(O(a+\log k)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x){
    return x=read<T>();
}
typedef long long ll;

co int mod=1e7+7;
struct data{
    ll v[3][3];
    data(int x=0){memset(v,0,sizeof v);v[0][0]=v[1][1]=v[2][2]=x;}
    ll*operator[](int a){return v[a];};
    co ll*operator[](int a)co{return v[a];};
    data operator*(co data&a)co{
        data re;
        for(int k=0;k<3;++k)
            for(int i=0;i<3;++i) if(v[i][k])
                for(int j=0;j<3;++j)
                    re[i][j]=(re[i][j]+v[i][k]*a[k][j])%mod;
        return re;
    }
}A;
int a[100001];
data pow(data x,int y){
    data re(1);
    while(y){
        if(y&1) re=re*x;
        x=x*x,y>>=1;
    }
    return re;
}
int main(){
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int n=read<int>(),k=read<int>();
    ll sum=0;
    for(int i=1;i<=n;++i)
        sum+=read(a[i]);
    std::sort(a+1,a+n+1);
    if(a[n]<=0) printf("%lld\n",((sum+(ll)(a[n]+a[n-1])*k)%mod+mod)%mod);
    else{
        for(sum-=a[n];k&&a[n-1]<0;--k)
            a[n-1]+=a[n],sum+=a[n-1];
        A[0][0]=A[0][1]=A[0][2]=A[1][0]=A[2][2]=1,A=pow(A,k+1);
        printf("%lld\n",((sum+a[n]*A[0][2]+a[n-1]*A[1][2])%mod+mod)%mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10410241.html