我的解决方案 - SPOJ - ALTSEQ 有什么问题

What is wrong with my solution - SPOJ - ALTSEQ?

本文关键字:什么 问题 SPOJ 解决方案 我的 ALTSEQ      更新时间:2023-10-16

我需要做什么:我需要在SPOJ上解决[这个]问题。

给定一个由 N 个整数 a1、a2、a3、...aN 我必须找到数组最长交替子序列的长度。
交替序列 b1, b2 ...bk, k>=1 是一个序列,具有以下 2 个属性:

  1. |b1|<|b2|<|b3|<.....<|bk|
  2. 符号在相邻元素之间交替,即,如果 b1> 0,则 b2<0、b3>0 等。或者,如果为 b1<0,则为 b2>0、b3<0 等。

我的方法:
该问题是最长递增子序列 (LIS) 问题的变体。这是我基于记忆的递归解决方案:

#include <cstdio>
using namespace std;
long *a;
int *dp;
int solve(int);
int main()
{
    int n;
    scanf("%d", &n);
    a = new long[n];
    dp = new int[n]{};
    for (int i = 0; i < n; i++) scanf("%ld", a+i);
    printf("%d", solve(n-1));
}
int solve(int n)
{
    if (dp[n]) return dp[n];
    int &m = dp[n] = 1, k;
    for(int j = 0; j < n; j++)
        if (((a[n] < 0 && a[j] > 0 && -a[n] > a[j]) || (a[n] > 0 && a[j] < 0 && a[n] > -a[j])))
            if ((k = 1 + solve(j)) > m) m = k;
    return m;
}

我的问题:这个解决方案在裁判系统上给出了错误的答案,所以它一定有问题。我需要帮助来找出此解决方案的问题所在,因为我无法独自一人。

后来我突然想到,solve(i) 正在计算 dp[i],即以第 i 个元素结尾的 LIS。因此,整个 dp 数组的最大值是正确答案,而不是我之前打印的 dp[n-1]。

此外,递归解决方案可以转换为自下而上以提高效率。此外,在自下而上的情况下,所涉及的两个环路中的外侧一个可以与输入读取环路相结合,并且可以在外环路本身内跟踪最大dp[i],以避免再次通过找到最大值。这应该会带来更快的解决方案。

#include <cstdio>
using namespace std;
int main()
{
    int n, k, m = 0;
    scanf("%d", &n);
    long *a = new long[n];
    int *dp = new int[n];
    for (int i = 0; i < n; i++) {
        scanf("%ld", a+i);
        dp[i] = 1;
        for (int j = 0; j < i; j++)
            if (((a[i] < 0 && a[j] > 0 && -a[i] > a[j]) || (a[i] > 0 && a[j] < 0 && a[i] > -a[j])) && (k = 1 + dp[j]) > dp[i]) dp[i] = k;
        if (dp[i] > m) m = dp[i];
    }
    printf("%dn", m);
}