C++ 长度k的递增子序列数
我试图理解一种算法,该算法给出了数组中长度K在时间O(nklog(n))内递增的子序列的数目。我知道如何使用O(k*n^2)算法来解决同样的问题。我查了一下,发现这个解决方案使用了BIT(Fenwick树)和DP。我还发现了一些代码,但我一直无法理解它 以下是我访问过的一些有用的链接C++ 长度k的递增子序列数,c++,algorithm,lis,fenwick-tree,C++,Algorithm,Lis,Fenwick Tree,我试图理解一种算法,该算法给出了数组中长度K在时间O(nklog(n))内递增的子序列的数目。我知道如何使用O(k*n^2)算法来解决同样的问题。我查了一下,发现这个解决方案使用了BIT(Fenwick树)和DP。我还发现了一些代码,但我一直无法理解它 以下是我访问过的一些有用的链接 如果有人能帮助我理解这个算法,我将不胜感激。我正在复制我的算法,其逻辑解释如下: dp[i, j] = same as before num[i] = how many subsequences that
如果有人能帮助我理解这个算法,我将不胜感激。我正在复制我的算法,其逻辑解释如下:
dp[i, j] = same as before num[i] = how many subsequences that end with i (element, not index this time)
have a certain length
for i = 1 to n do dp[i, 1] = 1
for p = 2 to k do // for each length this time num = {0}
for i = 2 to n do
// note: dp[1, p > 1] = 0
// how many that end with the previous element
// have length p - 1
num[ array[i - 1] ] += dp[i - 1, p - 1] *1*
// append the current element to all those smaller than it
// that end an increasing subsequence of length p - 1,
// creating an increasing subsequence of length p
for j = 1 to array[i] - 1 do *2*
dp[i, p] += num[j]
您可以使用段树或二元索引树来优化*1*
和*2*
。这些将用于有效地处理num
数组上的以下操作:
- 给定
将(x,v)
添加到v
(与num[x]
相关)李>*1*
- 给定
,求和x
(与num[1]+num[2]+…+num[x]
相关)*2*
O(n*k*log S)
,其中S
是数组中值的上限。这可能不够好,也可能不够好。要使其O(n*k*logn)
,需要在运行上述算法之前规范化数组的值。规范化意味着将所有数组值转换为小于或等于n
的值。因此:
5235 223 1000 40 40
变成:
4 2 3 1 1
这可以通过排序(保留原始索引)来实现。注意显示您发现的具有O(nklog(n))复杂性的代码吗?topcoder链接现在已修复。你们可以在那个里找到它。不需要马上用BIT就可以更容易地思考这个问题。我在这里解释:我无法理解你的算法。你能在我的帖子中详细解释一下吗?也许能给我一个关于使用段树的想法,然后我会用BIT提出一个解决方案。提前谢谢,我补充了一些解释。如果您仍然无法理解它,请确切地告诉我有什么不清楚的地方,我会尽力帮助您。有些事情我还无法理解。该算法如何保证存储不断增加的子序列的数量。我知道DP O(nnk)是怎么做的,但是这个。。。不是clue@Andrés-基本上,您可以计算每个值在特定长度中的数量(不像经典DP中的索引)。可以将当前值附加到所有较小的值,获得+1长度。