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;
}
View Code

 

posted @ 2016-04-11 21:36  117208  阅读(294)  评论(0编辑  收藏  举报