标签:while max 最小 inline 并且 cal 时间复杂度 优化 暴力
将一个序列分为\(m\)段\((m\)自己决定\()\)并且每一段的和递增 求\(\sum_{i=0}^m s_i ^ 2\)
\(s_i\)为每一段的和
比较好想 \(f[i][j]\)表示最后一段尾部端点尾\(i\) 头端点为\(j\) 的最小代价
\[f[i][j] = max(f[j][k] + sqr((s[i] - s[j])))\]
可以优化一下枚举\(i,j\)然后二分找到\(k\) 时间复杂度\(O(n^2 \log n)\)
可以证明如果一个区间大于前面的区间 且可以分为 \(\text {a b (pre <= a <= b})\)
那么将他分开一定是最优的 那么对于一个\(i\) 我们去维护一个\(f[i]\)并且使得\(s[i] - s[f[i]]\)最小化 答案一定是最优的
我们可以\((n^2)\)找到一个最优的\(f[i]\)然后就得到了\(64pts\)的高分
暴力\(O(n ^ 2)\)未免太暴力了 我们可以想满足条件 \(s[i] - s[j] >= s[j] - s[f[j]]\)
移项可得\(s[i] >= s[j] * 2 - s[f[j]]\) 我们只需找到最后一个满足这个条件的值
然后\(f[i] = j\)就行了 这个东西可以用单调队列去写
int head = 1, tail = 1;
for (int i = 1; i <= n; i ++ ) {
while (head < tail && calc (q[head + 1]) <= s[i]) head ++ ;
g[i] = q[head];
while (head < tail && calc (q[tail]) >= calc (i)) tail -- ;
q[++tail] = i;
}
for (int i = n; i >= 1; i = g[i]) ans = (ans + sqr (s[i] - s[g[i]]));
\(36\)比较\(\text{navie}\)难度普及
\(64\) 分析性质 难度提高
\(100\) 用单调队列维护不难想 关键是前面一步的证明 难度提高+
标签:while max 最小 inline 并且 cal 时间复杂度 优化 暴力
原文地址:https://www.cnblogs.com/Hock/p/12213135.html