萌萌哒的链接
题解:
题目在求一串序列的最长递增子序列的基础上,再求其数量。看到题目的数的范围,一眼就应该想到先离散。
离散完后,再仔细想想,咦,不是可以用n^2的dp做吗? 对于序列的第i位,其最优子结构为求出值比a[i]小的
且当前最长递增子序列是最大的。然后我们再加个计数就行了?。。。。
事实证明这个不妥,因为题目的序列最大有50000,n^2的算法一秒之内肯定过不了。于是我们想到了一个神奇
的数据结构,线段树。我们可以维护一个长为序列长度的线段树。然后对于序列的第i位,我们可以在logn的基础
上求得答案。 然后这题的时间复杂度就控制在nlogn了。
AC代码:
#include <bits/stdc++.h> using namespace std; #define ls u << 1 #define rs u << 1 | 1 #define mid (l + r >> 1) #define lson l,mid,u<<1 #define rson mid + 1,r,u<<1|1 const int N = 50000 + 5; const int mod = 1000000007; typedef pair<int,int> P; int a[N]; vector<int> p; inline int ID(int x) { return lower_bound(p.begin(),p.end(),x) - p.begin() + 1; } struct Tree { int Max[N << 2],Num[N << 2]; void pushup(int u) { Max[u] = Max[ls]; Num[u] = Num[ls]; if(Max[u] == Max[rs]) Num[u] = (Num[u] + Num[rs]) % mod; if(Max[u] < Max[rs]) { Max[u] = Max[rs]; Num[u] = Num[rs]; } } P que(int l,int r,int u,int x,int y) { if(x <= l && y >= r) return make_pair(Max[u],Num[u]); else { P pb={0,0}; if(x <= mid) pb = que(lson,x,y); if(y > mid) { P tp = que(rson,x,y); if(tp.first > pb.first) pb = tp; else if(tp.first == pb.first) pb.second = (pb.second + tp.second) % mod; } return pb; } } void update(int l,int r,int u,int x,int val,int num) { if(l == r) { if(Max[u] < val) { Max[u] = val; Num[u] = num % mod; } else if(Max[u] == val) { Num[u] = (Num[u] + num) % mod; } } else { if(x <= mid) update(lson,x,val,num); else update(rson,x,val,num); pushup(u); } } }ac; int main() { int n; cin>>n; for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); p.push_back(a[i]); } sort(p.begin(),p.end()); p.erase(unique(p.begin(),p.end()),p.end()); int Maxlen,MaxNum; Maxlen = MaxNum = 0; int m = n; n = p.size(); for(int i = 1; i <= m; i++) { P pb = {0,1}; int id = ID(a[i]); if(id > 1) pb = ac.que(1,n,1,1,id -1); if(pb.first == 0) { pb.second = 1; } pb.first++; if(pb.first > Maxlen) { Maxlen = pb.first; MaxNum = pb.second; } else if(pb.first == Maxlen) { MaxNum = (MaxNum + pb.second) % mod; } ac.update(1,n,1,id,pb.first,pb.second); } cout<<MaxNum<<endl; return 0; }