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

    n<=3000个数划分成m段,每段的权值为这一段数字的和,求段的最小方差乘上m平方。

    所以就是求上边那组平方和的最小值,这个可以dp,f(i,j)表示分成i段,前j个数最小方差,

    pre表示前缀和,这个式子可以用斜率优化或决策单调性解决。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 #include<algorithm>
     5 //#include<iostream>
     6 using namespace std;
     7 
     8 int n,m;
     9 #define maxn 3011
    10 int a[maxn],f[2][maxn],sum[maxn],cur;
    11 int head,tail,que[maxn];
    12 double play(int x,int y)
    13 {
    14     return ((f[cur^1][x]-f[cur^1][y])*1.0/(sum[x]-sum[y])+sum[x]+sum[y])/2;
    15 }
    16 const int inf=0x3f3f3f3f;
    17 int main()
    18 {
    19     scanf("%d%d",&n,&m);
    20     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    21     sum[0]=0;for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
    22     cur=0;for (int i=1;i<=n;i++) f[cur][i]=inf;f[cur][0]=0;
    23     for (int i=1;i<=m;i++)
    24     {
    25         cur^=1;
    26         f[cur][0]=inf;
    27         head=tail=0;que[tail++]=0;
    28         for (int j=1;j<=n;j++)
    29         {
    30             while (tail-head>1 && play(que[head+1],que[head])<sum[j]) head++;
    31             f[cur][j]=f[cur^1][que[head]]+(sum[j]-sum[que[head]])*(sum[j]-sum[que[head]]);
    32             while (tail-head>1 && play(que[tail-1],que[tail-2])>play(j,que[tail-1])) tail--;
    33             que[tail++]=j;
    34 //            cout<<f[cur][j]<<' ';
    35         }
    36 //        cout<<endl;
    37     }
    38     printf("%d
    ",m*f[cur][n]-sum[n]*sum[n]);
    39     return 0;
    40 }
    View Code
  • 相关阅读:
    问题 D: 错误探测
    问题 C: 计算矩阵边缘元素之和
    同行列对角线的格子
    矩形交换行
    问题 R: 鸡尾酒疗法
    问题 : 字符串p型编码
    循环结构 整数的个数
    字符串c++字符环
    ISBN码字符串c++
    Uva
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7654420.html
Copyright © 2011-2022 走看看