将阵列分成更小的连续部分,以使 NEO 值最大化
Divide array into smaller consecutive parts such that NEO value is maximal
今年泡泡杯(已完成(有问题NEO(我无法解决(,它要求
给定具有 n 个整数元素的数组。我们将其分为几个部分(可能是1个(,每个部分都是一个连续的元素。在这种情况下,NEO 值的计算公式为: 每个零件的值总和。部件的值是该部件中所有元素的总和乘以其长度。
示例:我们有数组:[ 2 3 -2 1 ]。如果我们像这样划分它:[2 3] [-2 1]。那么 NEO = (2 + 3( * 2 + (-2 + 1( * 2 = 10 - 2 = 8。
数组中的元素数小于10^5
个,数字是介于-10^6
和10^6
之间的整数
我已经尝试过诸如分而治之之类的方法,如果它增加了最大NEO数,则不断将阵列分成两部分,否则返回整个阵列的NEO。但不幸的是,该算法具有最坏情况 O(N^2( 复杂性(我的实现如下(,所以我想知道是否有更好的解决方案
编辑:我的算法(贪婪(不起作用,例如[1,2,-6,2,1]
我的算法返回整个数组,而获得最大 NEO 值是取部分[1,2],[-6],[2,1]
,这给出了 NEO 值(1+2)*2+(-6)+(1+2)*2=6
#include <iostream>
int maxInterval(long long int suma[],int first,int N)
{
long long int max = -1000000000000000000LL;
long long int curr;
if(first==N) return 0;
int k;
for(int i=first;i<N;i++)
{
if(first>0) curr = (suma[i]-suma[first-1])*(i-first+1)+(suma[N-1]-suma[i])*(N-1-i); // Split the array into elements from [first..i] and [i+1..N-1] store the corresponding NEO value
else curr = suma[i]*(i-first+1)+(suma[N-1]-suma[i])*(N-1-i); // Same excpet that here first = 0 so suma[first-1] doesn't exist
if(curr > max) max = curr,k=i; // find the maximal NEO value for splitting into two parts
}
if(k==N-1) return max; // If the max when we take the whole array then return the NEO value of the whole array
else
{
return maxInterval(suma,first,k+1)+maxInterval(suma,k+1,N); // Split the 2 parts further if needed and return it's sum
}
}
int main() {
int T;
std::cin >> T;
for(int j=0;j<T;j++) // Iterate over all the test cases
{
int N;
long long int NEO[100010]; // Values, could be long int but just to be safe
long long int suma[100010]; // sum[i] = sum of NEO values from NEO[0] to NEO[i]
long long int sum=0;
int k;
std::cin >> N;
for(int i=0;i<N;i++)
{
std::cin >> NEO[i];
sum+=NEO[i];
suma[i] = sum;
}
std::cout << maxInterval(suma,0,N) << std::endl;
}
return 0;
}
这不是一个完整的解决方案,但应该提供一些有用的方向。
-
将每组都有一个正和(或其中一个总和是非负的(组合在一起,总是会产生比将它们分开更大的 NEO:
m * a + n * b < (m + n) * (a + b) where a, b > 0 (or a > 0, b >= 0); m and n are subarray lengths
将负和的组与整个非负数组合并总是 比仅将其与非负组的一部分合并产生更大的NEO。但是排除负数和的组可能会产生更大的NEO:
[1, 1, 1, 1] [-2] => m * a + 1 * (-b)
现在,假设我们逐渐将分界线向左移动,增加总和 b 的组合。虽然右边的表达式是负数,但左组的近地天体一直在减少。但是,如果右边的表达式变得正,依靠我们的第一个断言(见1(,将两组结合起来总是大于不
。单独按顺序组合负数总是会产生比将它们分开更小的NEO:
-a - b - c ... = -1 * (a + b + c ...)
l * (-a - b - c ...) = -l * (a + b + c ...)
-l * (a + b + c ...) < -1 * (a + b + c ...) where l > 1; a, b, c ... > 0
O(n^2)
时间,O(n)
空间 JavaScript 代码:
function f(A){
A.unshift(0);
let negatives = [];
let prefixes = new Array(A.length).fill(0);
let m = new Array(A.length).fill(0);
for (let i=1; i<A.length; i++){
if (A[i] < 0)
negatives.push(i);
prefixes[i] = A[i] + prefixes[i - 1];
m[i] = i * (A[i] + prefixes[i - 1]);
for (let j=negatives.length-1; j>=0; j--){
let negative = prefixes[negatives[j]] - prefixes[negatives[j] - 1];
let prefix = (i - negatives[j]) * (prefixes[i] - prefixes[negatives[j]]);
m[i] = Math.max(m[i], prefix + negative + m[negatives[j] - 1]);
}
}
return m[m.length - 1];
}
console.log(f([1, 2, -5, 2, 1, 3, -4, 1, 2]));
console.log(f([1, 2, -4, 1]));
console.log(f([2, 3, -2, 1]));
console.log(f([-2, -3, -2, -1]));
更新
此博客提供了我们可以从
dp_i = sum_i*i + max(for j < i) of ((dp_j + sum_j*j) + (-j*sum_i) + (-i*sumj))
自
dp_i = sum_i*i + max(for j < i) of (dp_j + sum_j*j, -j, -sum_j) ⋅ (1, sum_i, i)
这意味着我们可以在每次迭代中查看已经看到的向量,该向量将使用我们当前的信息生成最大的点积。提到的数学涉及凸包和最远点查询,这在这一点上超出了我的能力范围,但会进行研究。
- 在数字之间插入 + 或 - 符号以使其等于整数
- 如何格式化我的文本文件以使其不会一遍又一遍地重复同一行?
- 如何在 c++ 中正确指定 #include 路径以使程序可移植
- 如何从Clojure调用C++程序,以使程序保持打开状态?
- 如何修复阵列以使其正确?
- C++如何简化此模板以使其不专业?
- 最大数量.给定一个非负整数列表,排列它们以使它们形成最大的数字
- 如何用逗号分隔输出?如何改进此代码以使其看起来更体面?
- Wxwidgets - 如何添加调整大小事件处理程序以使"X"绘图随窗口调整大小?
- 将阵列分成更小的连续部分,以使 NEO 值最大化
- 我将如何获得正确的公式结构以使我的程序C++中的侧 c?
- 有没有办法在带有空格C++源代码中写入大量数字以使其更具可读性?
- C++ 传递对数组的引用以使其发挥作用
- 如何更改 int 以使其具有较小的字段来选择随机数
- 我需要将阵列样式的邻接矩阵转换为矢量样式(以使其看起来更好)
- 代码 C++ 以添加前缀关键字以使其有效
- 如何修复下一个线程以使其更正确?使用 Pthread
- 从2011年开始,必须在2019年开始工作以使此Windows Textbox做出哪些更改
- 如何在 libgit2 中设置结帐选项以使其表现得像"git checkout"
- 重写类以使其更通用,以实现可移植性