zoukankan      html  css  js  c++  java
  • bzoj4518[Sdoi2016]征途

    bzoj4518[Sdoi2016]征途

    题意:

    n个数,分成m段使每段和的方差尽可能小。

    题解:

    朴素的dp方程:f[i,m]=f[j,m-1]+(sum[i]-sum[j])2,j∈[1,i-1](sum[i]-sum[j]不用减平均数的原因是最后可以化简成f[n,m]*m-sum[n])复杂度为O(n3)会T,因为有个平方,所以考虑斜率优化,化简得到f[j,m-1]比f[k,m-1]好当且仅当((f[j,m-1]+sum[j]2)-(f[k,m-1]+sum[k]2))<2*sum[i]*(sum[j]-sum[k]),因为递推时是从小到大的顺序,所以sum[j]-sum[k]<0,所以((f[j,m-1]+sum[j]2)-(f[k,m-1]+sum[k]2))/(sum[j]-sum[k])>2*sum[i],用单调队列即可。多的那一维可以用滚动数组省空间。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define maxn 5000
     5 #define inc(i,j,k) for(int i=j;i<=k;i++)
     6 using namespace std;
     7 
     8 long long x[maxn],y[maxn],sum[maxn],a[maxn];int q[maxn],n,m,l,r;
     9 inline long long sqr(long long x){return x*x;}
    10 inline double get(long long a1,long long a2){
    11     return (double)((x[a1]+sqr(sum[a1]))-(x[a2]+sqr(sum[a2])))/(double)(sum[a1]-sum[a2]);
    12 }
    13 int main(){
    14     scanf("%d%d",&n,&m); sum[0]=0; inc(i,1,n)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
    15     inc(i,1,n)x[i]=sqr(sum[i]);
    16     inc(i,2,m){
    17         l=0,r=0; memset(y,0,sizeof(y)); x[1]=sqr(sum[1]); q[l]=1;
    18         inc(j,2,n){
    19             while(l<r&&get(q[l],q[l+1])<2*sum[j])l++;
    20             while(l<r&&get(q[r-1],q[r])>get(q[r],j))r--;
    21             q[++r]=j; y[j]=x[q[l]]+sqr(sum[j]-sum[q[l]]);
    22         } swap(x,y);
    23     }
    24     printf("%lld",(x[n])*(long long)m-sqr(sum[n]));
    25 }

    20160423

  • 相关阅读:
    Path类
    C#集合
    阿里巴巴2013年实习生笔试题B
    阿里巴巴2013年实习生笔试题A
    腾讯2014年校园招聘笔试试题
    腾讯技术类校园招聘笔试试题
    腾讯2013年实习生笔试题
    腾讯2012年实习生笔试题
    hdu1505
    hdu1506
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5703328.html
Copyright © 2011-2022 走看看