[hdu6991]Increasing Subsequence

令$f_{i}$​​表示以$i$​​为结尾的极长上升子序列个数,则有$f_{i}=sum_{j<i,a_{j}<a_{i},forall j<k<i,a_{k} otin [a_{j},a_{i}]}f_{j}$

(初始状态为前缀最小值处$f_{i}=1$,最终答案为后缀最大值处的$f_{i}$​之和)

暴力计算复杂度显然为$o(n^{2})$,无法通过

考虑分治计算,当递归到区间$[l,r]$时,需要求出仅考虑$[l,r]$内部的(包括转移的$j$)时的$f_{i}$

具体的,先递归$[l,mid]$,再求出$[l,mid]$对$(mid,r]$的影响,最后递归$(mid,r]$即可

第一步和第三步容易处理,接下来考虑第二步:

具体的,考虑将$a_{l},a_{l+1},...,a_{r}$从小到大排序后枚举,注意到此时左侧的数中,如果存在$x<y$且$a_{x}<a_{y}$,那么$x$一定不会被使用(因为之后右侧的$a_{i}>a_{y}$​​),也即可以维护一个单调栈

(关于这个单调栈,从栈底到栈顶位置单调递减、权值单调递增)

类似地,我们再对右侧维护一个单调栈,从栈底到栈顶位置和权值都单调递增,此时即查询比左边单调栈中比当前比右边单调栈栈顶(插入前,若为空则定义为0)大的位置的$f$之和,可以二分实现

由于需要排序和二分,总复杂度为$o(nlog^{2}n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define mod 998244353
 5 int t,n,ans,a[N],id[N],stl[N],str[N],sum[N],f[N];
 6 bool cmp(int x,int y){
 7     return a[x]<a[y];
 8 }
 9 void calc(int l,int r){
10     if (l==r)return;
11     int mid=(l+r>>1);
12     calc(l,mid);
13     for(int i=l;i<=r;i++)id[i]=i;
14     sort(id+l,id+r+1,cmp);
15     stl[0]=str[0]=0;
16     for(int i=l;i<=r;i++){
17         if (id[i]<=mid){
18             while ((stl[0])&&(stl[stl[0]]<id[i]))stl[0]--;
19             stl[++stl[0]]=id[i];
20             sum[stl[0]]=(sum[stl[0]-1]+f[id[i]])%mod;
21         }
22         else{
23             while ((str[0])&&(str[str[0]]>id[i]))str[0]--;
24             int pos=lower_bound(stl+1,stl+stl[0]+1,str[str[0]],cmp)-stl;
25             str[++str[0]]=id[i];
26             f[id[i]]=(f[id[i]]+(sum[stl[0]]-sum[pos-1]+mod)%mod)%mod;
27         }
28     }
29     calc(mid+1,r);
30 }
31 int main(){
32     scanf("%d",&t);
33     while (t--){
34         scanf("%d",&n);
35         for(int i=1;i<=n;i++)scanf("%d",&a[i]);
36         int s=n+1;
37         for(int i=1;i<=n;i++){
38             f[i]=(a[i]<s);
39             s=min(s,a[i]);
40         }
41         calc(1,n);
42         s=ans=0;
43         for(int i=n;i;i--){
44             if (a[i]>s)ans=(ans+f[i])%mod;
45             s=max(s,a[i]);
46         }
47         printf("%d
",ans);
48     }
49     return 0;
50 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15095404.html