UOJ 104 [APIO2014]Split the sequence

首先发现如果切同样的地方,先切后切都一样,即操作顺序没影响,这样满足无后效性就可以DP了

f[i][j] 表示前i的序列,切j次最大答案

于是得到裸方程: f[i][j]=max(f[k][j1]+sum[k](sum[i]sum[k]))(k<i)

复杂度 O(n2k) 太大,进行斜率优化

假设g < k,k比g优

f[k][j1]+sum[k](sum[i]sum[k])f[g][j1]sum[g](sum[i]sum[g])>0

整理

(f[k][j1]sum[k]2)(f[g][j1]sum[g]2)sum[k]sum[g]>sum[i]

斜率 sum[i] 单调递减,那么维护上凸壳即可

被细节坑死!代码里的分母是负的,忘记变不等号,调了半天。。。
队列里面只装下标,装带x,y的结构体会强行TLE
多余的维要压掉

#include<cstdio>
#include<cstring>
#define MAXN 100005
#define MAXK 205
using namespace std;
long long sum[MAXN], f[MAXN][2],y[MAXN],x[MAXN];
int from[MAXN][MAXK],q[MAXN];
int in(){
    char ch;int aa;
    while(ch=getchar(),ch<'0'||ch>'9');aa=ch-'0';
    while(ch=getchar(),ch>='0'&&ch<='9')aa=aa*10+ch-'0';return aa;
}
int main()
{
    int n=in(), k=in();
    for(int i = 1; i <= n; i++)
        sum[i]+=sum[i-1]+in();
    int cur = 1, last=0;
    for(int j = 1; j <= k; j++)
    {
        int head=0,tail=1;
        cur^=1;last^=1;
        x[0]=sum[j];
        y[0]=f[j][last]-sum[j]*sum[j];
        q[0]=j;
        for(int i = j+1; i <= n; i++)
        {
            //正负 
            while(tail-head>1 && (y[head]-y[head+1])<=(-sum[i])*(x[head]-x[head+1]))head++;     
            f[i][cur]=y[head]+sum[i]*x[head];       
            long long nowx=sum[i], nowy=f[i][last]-sum[i]*sum[i];                   
            from[i][j]=q[head];     
            while(tail-head>1 && (x[tail-1]-x[tail-2])*(nowy-y[tail-2])-(nowx-x[tail-2])*(y[tail-1]-y[tail-2])>=0)tail--;   
            x[tail]=nowx;
            y[tail]=nowy;       
            q[tail++]=i;
        }   
    }
    printf("%lld\n",f[n][cur]);
    for(int i = k; i; i--)
    {
        n=from[n][i];
        printf("%d ",n);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值