bzoj3675: [Apio2014]序列分割

BZOJ3675 [Apio2014]序列分割

link:http://www.lydsy.com/JudgeOnline/problem.php?id=3675

简介

  网上大佬的题解都那么复(qi)杂(guai)。。。
  然而我做着感觉很轻松哎。。难道是我做错了?

题解

   fi,kik
  那么

fi,k=max{(sisj)×sj+fj,k1}

  为了好看把k这一维去掉,令 gj=fj,k1 fifi,k
  那么
fi=max{gj+(sisj)×sj}

  把max去掉得到
fi=(gjs2j)+si×sj

  那么 fi 就是截距,由于 sj 是单调不下降的所以把它作为横坐标,那么 (gjs2j) 就是纵坐标了
  为了好看再写一步,
  令 xj=sj yj=(gjs2j)
  那么原方程化为
fi=si×xi+yi

  斜率 (si) 是单调不上升的,因此我们可以使用单调队列维护上凸壳,时间复杂度 O(NK)
  有一个坑点:因为横坐标是单调不下降的,所以就有可能出现斜率不存在的直线,此时分母为0,应当特判

#include <cstdio>
#include <algorithm>
#define maxn 100010
#define maxk 210
#define ll long long
using namespace std;
struct point{ll x, y;double k;}q[maxn];
ll f[2][maxn], s[maxn], N, K;
ll read(ll x=0){scanf("%lld",&x);return x;}
void init()
{
    ll i, a;
    N=read();K=read();
    for(i=1;i<=N;i++)a=read(),s[i]=a+s[i-1];
}
void work(ll *f, ll *g, ll c)
{
    ll l=1, r=1, i, x, y, flag;
    q[r++]=(point){s[c],g[c]-s[c]*s[c],0};
    for(i=c+1;i<=N;i++)
    {
        while(l<r-1 and -s[i]<q[l+1].k)l++;
        f[i]=q[l].y+s[i]*q[l].x;
        x=s[i],y=g[i]-s[i]*s[i];
        if(x==q[r-1].x and y>q[r-1].y)r--;
        else if(x==q[r-1].x and y<=q[r-1].y)continue;
        while(r-1>l and double(y-q[r-1].y)/(x-q[r-1].x) > q[r-1].k)r--;
        q[r]=(point){x,y,double(y-q[r-1].y)/(x-q[r-1].x)},r++;
    }
}
int main()
{
    ll i;
    init();
    for(i=1;i<=K;i++)work(f[i&1],f[~i&1],i);
    printf("%lld\n",f[K&1][N]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值