SDOI 2016 征途 决策单调性
题目大意:有一个数列,将其分成m段,求最小方差
先弄出n^3的dp,打出决策点,然后发现决策点是单调递增的,决策单调性搞一搞就可以了
#include<bits/stdc++.h> #define ll long long #define maxn 3010 using namespace std; int n,m; int a[maxn],sum[maxn]; double f[maxn][maxn],x; double sqr(double x){return x*x;} void solve(double f1[],double f2[],int l,int r,int L,int R){ if(l>r)return; double t=1e20;int k; int mid=(l+r)>>1; for(int i=L;i<=R;++i){ double p=f1[i]+sqr(sum[mid]-sum[i]-x); if(p<t)t=p,k=i; } f2[mid]=t; solve(f1,f2,l,mid-1,L,k); solve(f1,f2,mid+1,r,k,R); } int main(){ freopen("menci_journey.in","r",stdin); freopen("menci_journey.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]); for(int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i]; x=1.0*sum[n]/m; for(int i=0;i<=m;++i) for(int j=0;j<=n;++j) f[i][j]=1e20; f[0][0]=0; for(int i=1;i<=m;++i) solve(f[i-1],f[i],1,n,i-1,n); printf("%lld\n",(ll)(f[m][n]*m+0.5)); return 0; }