bzoj3675: [Apio2014]序列分割
斜率优化。假如我讲不清楚就去%星感大神的题解吧
我一开始想了个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; }
pain and happy in the cruel world.