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

  • 相关阅读:
    2017ccpc全国邀请赛(湖南湘潭) E. Partial Sum
    Codeforces Round #412 C. Success Rate (rated, Div. 2, base on VK Cup 2017 Round 3)
    2017 中国大学生程序设计竞赛 女生专场 Building Shops (hdu6024)
    51nod 1084 矩阵取数问题 V2
    Power收集
    红色的幻想乡
    Koishi Loves Segments
    Wood Processing
    整数对
    Room and Moor
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5703328.html
Copyright © 2011-2022 走看看