[SDOI2016] 征途题解

P4072 [SDOI2016] 征途

题目描述

Pine 开始了从 SSS 地到 TTT 地的征途。

SSS 地到 TTT 地的路可以划分成 nnn 段,相邻两段路的分界点设有休息站。

Pine 计划用 mmm 天到达 TTT 地。除第 mmm 天外,每一天晚上 Pine 都必须在休息站过夜。所以,一段路必须在同一天中走完。

Pine 希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。

帮助 Pine 求出最小方差是多少。

设方差是 vvv,可以证明,v×m2v\times m^2v×m2 是一个整数。为了避免精度误差,输出结果时输出 v×m2v\times m^2v×m2

输入格式

第一行两个数 n,mn, mn,m

第二行 nnn 个数,表示 nnn 段路的长度。

输出格式

一个数,最小方差乘以 m2m^2m2 后的值。

输入输出样例 #1

输入 #1

5 2
1 2 5 8 6

输出 #1

36

说明/提示

数据范围及约定

  • 对于 30%30\%30% 的数据,1≤n≤101 \le n \le 101n10
  • 对于 60%60\%60% 的数据,1≤n≤1001 \le n \le 1001n100
  • 对于 100%100\%100% 的数据,1≤n≤30001 \le n \le 30001n3000

保证从 SSSTTT 的总路程不超过 3×1043\times 10^43×104

2≤m≤n2 \leq m \leq n2mn,每段路的长度为不超过 3×1043 \times 10^43×104正整数

思路

单调队列
斜率优化

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,m,a[3005],b[3005],f[3005][3005],op=0;
int main(){
	cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=b[i-1]+a[i];
    }
    memset(f,62,sizeof(f));
    for(int i=1;i<=n;i++){
        f[i][1]=b[i]*b[i];
        for(int j=2;j<=min((long long)i,m);j++){
            f[i][j]=1e18+7;
            for(int k=max(0,i-100);k<=i-1;k++){
                f[i][j]=min(f[i][j],f[k][j-1]+(b[i]-b[k])*(b[i]-b[k]));
            }
            //cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
        }
    }
    cout<<f[n][m]*m-b[n]*b[n]<<endl;
	return 0;
}
posted @ 2025-12-18 21:28  bz02_2023f2  阅读(1)  评论(0)    收藏  举报  来源