• 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
  • 相关阅读:
    【排序算法汇总】
    Redis是否安装
    分布式与集群
    Redis学习
    简单算法定义见解
    KMP算法
    红黑树
    JSP与Servlet的关系
    7、创建图及图的遍历(java实现)
    6、二叉树树(java实现)
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7654420.html
Copyright © 2020-2023  润新知