1. 程式人生 > >bzoj3675: [Apio2014]序列分割

bzoj3675: [Apio2014]序列分割

不同 scan i++ d+ lld names eof 通過 一個數

斜率優化。假如我講不清楚就去%星感大神的題解吧

我一開始想了個O(kn^3)的

就是枚舉k和n,然後枚舉前面的點,然後枚舉前面的點到當前點在哪斷最優。

而O(kn^2)咋搞呢

我通過畫圖發現(其實是某人告訴了我分配律的問題)

樣例最後斷出來是這樣的

(4),(1,3),(4,0),(2,3)

然後答案其實就是每一個數和其他不同組的數乘一次

DP方程就得出是這樣的:f[i][now]=f[j][now^1]+s[j]*(s[i]-s[j]);

其中now是滾動數組滾動枚舉k的t

然後斜率優化。

但是有一個狗比問題,就是s[j1]==s[j2],這時除數為0要特判

星感大神說他調樣例的時候發現的。

然而我的就玄學過了樣例。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL a[110000],s[110000],f[110000][2];

int now;
double Y(int j){return double(f[j][now^1]-s[j]*s[j]);}
double X(int j){return double(s[j]);} double slope(int j1,int j2){return (Y(j1)-Y(j2))/(X(j2)-X(j1));} int head,tail,list[110000]; int main() { int n,m; scanf("%d%d",&n,&m); s[0]=0; for(int i=1;i<=n;i++) scanf("%lld",&a[i]), s[i]=s[i-1]+a[i]; memset(f,
0,sizeof(f));now=0; for(int t=1;t<=m;t++)//第t次 cut { now^=1; head=1,tail=1;list[head]=t; for(int i=t+1;i<=n;i++) { while(head!=tail&&(slope(list[head],list[head+1])<double(s[i])||s[list[head]]==s[list[head+1]]))head++; int j=list[head]; f[i][now]=f[j][now^1]+s[j]*(s[i]-s[j]); while(head!=tail&&(s[i]==s[list[tail]]||slope(list[tail-1],list[tail])>slope(list[tail],i)))tail--; list[++tail]=i; } } printf("%lld\n",f[n][now]); return 0; }

bzoj3675: [Apio2014]序列分割