【HDU 3045】Picnic Cows

还是要先排序

设sum[i]为兴趣值的前缀和

设DP[i]为目前为止最优的分组

则DP[i]=min(DP[j]+sum[i]-sum[j]-a[j]*(i-j+1))

设k<j&&j决策更优

DP[j]+sum[i]-sum[j]-a[j]*(i-j+1)<DP[k]+sum[i]-sum[k]-a[k]*(i-k+1)

==>DP[j]-sum[j]-a[j]+a[j]*j-(DP[k]-sum[k]-a[k]+a[k]*k)<(a[j]-a[k])*i

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SIZEN=400050;
const LL INF=1ll<<50;
LL dp[SIZEN];
LL a[SIZEN],s[SIZEN];
int q[SIZEN];
int head,tail;
LL read(){
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    LL ans=0,flag=1;
    if(ch=='-'){flag=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans*flag;
}
LL getup(int k,int j){
    return dp[j]-s[j]+a[j+1]*j-(dp[k]-s[k]+a[k+1]*k);
}
LL getdown(int k,int j){
    return a[j+1]-a[k+1];
}
LL getval(int i,int j){
    return dp[j]+s[i]-s[j]-a[j+1]*(i-j);
}
void solve(int n,int m){
    for(int i=1;i<=n;i++) a[i]=read();
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    dp[0]=a[0]=s[0]=0;
    head=tail=0;
    q[tail++]=0;
    for(int i=m,j=1;i<=n;i++,j++){
        while(head+1<tail){
            LL dy=getup(q[head],q[head+1]);
            LL dx=getdown(q[head],q[head+1]);
            if(dy<=i*dx) head++;
            else break;
        }
        dp[i]=getval(i,q[head]);
        if(j<m) continue;
        while(head+1<tail){
            LL dy1=getup(q[tail-2],q[tail-1]);
            LL dx1=getdown(q[tail-2],q[tail-1]);
            LL dy2=getup(q[tail-1],j);
            LL dx2=getdown(q[tail-1],j);
            if(dy1*dx2>=dy2*dx1) tail--;
            else break;
        }
        q[tail++]=j;
    }
    printf("%I64d\n",dp[n]);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
        solve(n,m);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值