您将获得由A [1],A [2] ..... A [N]表示的N个整数A的序列。 序列中的每个整数都有一个与之关联的值W [1],W [2]…。 W [N]。 您必须选择给定数组A的子序列,以使A中的所有元素严格按递增顺序排列,并且此选定子序列中的元素值之和最大。您必须打印此最大值。
样本输入
2
4
1 2 3 4
100 200 300 400
3
4 2 3
100 30 20
样本输出
1000
100
我尝试使用动态编程解决此问题,但是我的代码的时间复杂度为n ^ 2,所以我想将其复杂度降低为nlogn,您能帮我吗?
这是我的实现方式
public class testing {
public static void main(String[] args) {
Scanner scn = new Scanner(System.in);
int t = scn.nextInt();
StringBuilder sb = new StringBuilder();
while (t-- > 0) {
int n = scn.nextInt();
int a[] = new int[n];
long val[] = new long[n];
for (int i = 0; i < n; i++) {
a[i] = scn.nextInt();
}
for (int i = 0; i < n; i++) {
val[i] = scn.nextLong();
}
long dp[] = new long[n];
Arrays.fill(dp, Integer.MIN_VALUE);
dp[0] = val[0];
for (int i = 1; i < n; i++) {
for (int j = i - 1; j >= 0; j--) {
if (a[j] < a[i]) {
dp[i] = Math.max(dp[i], dp[j] + val[i]);
}
}
}
long ans = Integer.MIN_VALUE;
for (long v : dp) {
ans = Math.max(v, ans);
}
sb.append(ans + "\n");
}
System.out.println(sb);
}
}
由于违规,我获得了TLE
约束 1 <= T <= 5 1 <= N <= 200000 1 <= a [i] <= 10 ^ 9,其中i∈[1..N] 1 <= w [i] <= 10 ^ 9,其中i∈[1..N]
答案 0 :(得分:2)
迭代一次,对于小于或等于给定A的A值,保持W值之和的TreeMap
,如对A值进行迭代时看到的那样。
对于新的A
,请调用lowerEntry(key)
方法以获取低于该新A的W的总和。
记住最大金额,然后将其返回。
单次迭代为 O(n),TreeMap
的使用为 O(log n),因此解决方案为 O(n log n ) * 。
static int sumIncreasing(int[] a, int[] w) {
int maxSum = Integer.MIN_VALUE;
TreeMap<Integer, Integer> sums = new TreeMap<>();
for (int i = 0; i < a.length; i++) {
Entry<Integer, Integer> lowerSum = sums.lowerEntry(a[i]);
int sum = (lowerSum != null ? lowerSum.getValue() + w[i] : w[i]);
sums.put(a[i], sum);
for (Entry<Integer, Integer> e; (e = sums.higherEntry(a[i])) != null && e.getValue() <= sum; )
sums.remove(e.getKey());
if (sum > maxSum)
maxSum = sum;
}
return maxSum;
}
*)内部for
循环为O(log n)(分期偿还,最坏的情况),因此它不会影响整体复杂性。 < / p>
测试
System.out.println(sumIncreasing(new int[] {1, 2, 3, 4}, new int[] {100, 200, 300, 400}));
System.out.println(sumIncreasing(new int[] {4, 2, 3}, new int[] {100, 30, 20}));
输出
1000
100