bzoj3675: [Apio2014]序列分割
阿新 • • 發佈:2018-03-15
不同 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]序列分割