【Codeforces 650 D】Zip-line

题意:给一个序列以及\(n\)个查询,每一个查询是问(假装)把第\(a_i\)个数改为\(b_i\)之后原序列的最长上升子序列的长度。

思路:线段树优化\(dp\)

肯定离线做啊。

首先我们考虑\(dp\)的状态是\(dp_L(i)\)表示以第\(i\)位为结束的最长上升子序列的长度和方案数\(mod\ 998244353\)

之所以方案数要模某个数是因为这个方案数太大太大了,肯定爆\(long\ long\)

就因为这个我\(wa\)了一次\(test\ case\ 13\)

开心的不得了呢

\(dp_R(i)\)的定义类似,只是以\(i\)为开始而已。

考虑转移,以\(dp_L\)为例。

\(dp_L(i)=dp_L(j)+1\)当且仅当\(j<i and a_j < a_i\)

那么这肯定可以用线段树来维护啊。

只需要用一个单点修改、区间查询的zkw就好了。

那么我们考虑把\(i\)换掉之后会发生什么。

首先新的LIS可以分成两部分考虑:

  • 必须包含新的数,那么就是我们可以考虑把\(i\)按照原来的\(dp\)方式转移,只不过需要添加查询数的\(dp\)值。
  • 不能包含新的数,那么有点难考虑。
    但是我们知道一个性质:如果我们所有的原来的LIS都经过这原来的数,
    那么现在不经过原来数的LIS最大也不会超过原来的-1,而且是肯定能够达到的。
    我们只需要统计经过原来这个数的LIS个数。
    也就是\(dp_L(i)*dp_R(i)\)

然后取必须包含这一位和必须不包含的\(max\)就是答案了。

猜你喜欢

转载自www.cnblogs.com/denverjin/p/10793592.html