BZOJ 3675: [Apio2014]序列分割

Description

將一個序列切割\(k\)次,每次切割的收益是兩邊和的乘積,求最大收益.\(n\leqslant 1\times 10^5,k\leqslant 200\)c++

Solution

斜率優化DP..優化

由於什麼\((a+b)c+ab=a(b+c)+bc\)..spa

因此他是隻與結果有關的,跟切割方法無關,隨便切就行...blog

\(f[i][j]=max\{f[k][j-1]+s[k](s[i]-s[k])\}\)ip

斜率正好是前綴和,而且單調不降..get

因此直接斜率優化那一套就好了...it

Code

/**************************************************************
    Problem: 3675
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:14596 ms
    Memory:84112 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
 
typedef long long LL;
const int N = 100005;
const int M = 205;
 
inline int in(int x=0,char ch=getchar()) { while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
 
int n,k;
int a[N],q[M][N],h[M],t[M];
LL s[N],f[N][2];
 
//#define B(i,j) (f[i][(j)&1]-s[i]*s[i])
//#define F(k,i,j) (B(k,((j)^1))+s[k]*s[i])
 
inline LL B(int i,int j) { return f[i][j&1]-s[i]*s[i]; }
inline LL F(int k,int i,int j) { return B(k,j^1)+s[k]*s[i]; }
 
int main() {
//  cout<<(sizeof(f)+sizeof(q)+sizeof(s)+sizeof(a))/1024.0/1024.0<<endl;
    n=in(),k=in();k++;
    for(int i=1;i<=n;i++) a[i]=in();
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
     
    for(int j=1;j<=k;j++) h[j]=1;
//  q[0][h[0]=t[0]=1]=0;
//  for(int i=1;i<=n;i++) f[i][1]=s[i];
    for(int j=2;j<=k;j++) {  
        q[j-1][h[j-1]=t[j-1]=1]=j-1;
        for(int i=j;i<=n;i++) {
            while(h[j-1]<t[j-1] && F(q[j-1][h[j-1]],i,j)<F(q[j-1][h[j-1]+1],i,j)) h[j-1]++;
            f[i][j&1]=F(q[j-1][h[j-1]],i,j);
//          cout<<i<<" "<<j<<" "<<q[j-1][h[j-1]]<<endl;
            while(h[j-1]<t[j-1] && 
                (s[q[j-1][t[j-1]]]-s[q[j-1][t[j-1]-1]])*(B(q[j-1][t[j-1]-1],j-1)-B(i,j-1))
                <=(s[i]-s[q[j-1][t[j-1]-1]])*(B(q[j-1][t[j-1]-1],j-1)-B(q[j-1][t[j-1]],j-1)))
                    t[j-1]--;
            q[j-1][++t[j-1]]=i;
        }
    }
//  for(int j=0;j<=1;j++) for(int i=1;i<=n;i++) printf("%lld%c",f[i][j]," \n"[i==n]);
    printf("%lld\n",f[n][k&1]);
    return 0;
}
相關文章
相關標籤/搜索