214*_*647 4 algorithm time search dynamic-programming
这是我想解决的问题,
您将获得一个包含2行和N列的表.每个单元格中都有一个整数.这样一个表的分数定义如下:对于每一列,考虑列中两个数字的总和; 如此获得的N个数的最大值是得分.例如,对于表格
7 1 6 2
1 2 3 4得分为max(7 + 1; 1 + 2; 6 + 3; 2 + 4)= 9.表的第一行是固定的,并作为输入给出.考虑第二行的N种可能方式:
1; 2; ::: ;; N
2; 3; ::: ;; N; 1
3; 4; ::: ;; N; 1; 2
|
N; 1; ::: ;; ; N 1例如,对于上面的示例,我们将以下各项视为第二行的可能性.
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3您的任务是找到第二行上述每个选项的分数.在上面的示例中,您将评估以下四个表,
7 1 6 2
1 2 3 4
7 1 6 2
2 3 4 1
7 1 6 2
3 4 1 2
7 1 6 2
4 1 2 3分别
计算得分9,10,10和11测试数据:N <= 200000
时间限制:2秒
这是一个显而易见的方法:
维护两个阵列A,B,执行以下n次
此方法将花费O(n ^ 2)时间,外部循环运行N次,并且有两个内部循环,每个循环运行N次.
为了减少所花费的时间,我们可以在第一行中找到最大元素M(在线性扫描中),然后在A [i] + N <= M + 1时删除A [i]和B [i].
因为他们永远不会是最大的.
但是这种方法在平均情况下可能表现更好,最坏情况时间仍然是O(N ^ 2).
为了在常量时间内找到最大值我也考虑使用堆,堆的每个元素都有两个属性,它们的原始值和要添加的值.但是,对于n个案例中的每一个,仍然需要线性时间来增加堆的所有元素的待添加值.
所以时间仍然是O(N ^ 2)
我无法找到一种能够比N ^ 2时间更快地解决这个问题的方法,因为N的值可能非常大,所以N ^ 2时间太慢.
任何帮助将不胜感激.
还有一种O(n)算法.使用与之前答案中相同的观察结果:
现在考虑将第二行向左旋转时列的总和会发生什么变化(例如将其从1,2,...,N更改为2,3,...,N,1):每列总和将增加除了一列减少了N-1之外,它除以1.
我们可以将一列总和减少N,而不是修改所有列总和,然后将最大列总和加1来查找列总和的新最大值.所以我们只需要更新一列而不是所有列.
当我们迭代第二行的可能性时,出现最大值的列只能向左移动或跳回到具有总体最大值的列.候选列是从左到右最大扫描中的临时最大值.
Taking the example input 7,1,6,2 the algorithm runs as follows: Step 1 calculates the sum 8,3,9,6 Step 2 finds the temporary maxima from left to right: 8 in col 1 and then 9 in col 3 Step 3 generates the results passing over the array from right to left
8 3 9 6 -> output 9 + 0 = 9
8 3 9 2 -> output 9 + 1 = 10
8 3 5 2 -> current max col is decreased, previous max 8 is larger and becomes current
output 8 + 2 = 10
8 -1 5 2 -> output 8 + 3 = 11
Run Code Online (Sandbox Code Playgroud)
这是C中的算法:
#include <stdio.h>
int N;
int A[200000];
int M[200000];
int main(){
int i,m,max,j,mval,mmax;
scanf("%d",&N);
for(i = 0;i < N; i++){
scanf("%d",&A[i]);
A[i] = A[i]+i+1;
}
m = 0;
max = 0;
M[0] = 0;
for(i = 1;i < N; i++){
if(A[i] > A[max]){
m++;
M[m] = i;
max = i;
}
}
mval = A[max] - N;
mmax = max;
for(i = N-1,j = 0;i >=0;i --,j++){
printf("%d ", A[max]+j);
A[i] = A[i] - N;
if(i == max){
if (A[i] < mval) {
max = mmax;
} else if(m > 0 && A[i] < A[M[m-1]]){
max = M[m-1];
m--;
}
}
}
printf("\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)