数组A包含N个整数(可能包含相同的值)。设S为A的子序列且S中的元素是递增的,则S为A的递增子序列。如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS)。A的LIS可能有很多个。例如A为:{1 3 2 0 4},1 3 4,1 2 4均为A的LIS。给出数组A,求A的LIS有多少个。由于数量很大,输出Mod 1000000007的结果即可。相同的数字在不同的位置,算作不同的,例如 {1 1 2} 答案为2。
题解:离线。线段树维护区间最长上升序列的长度和个数。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define lc idx<<1 #define rc idx<<1|1 #define lson l,mid,lc #define rson mid+1,r,rc #define mod 1000000007 using namespace std; typedef long long ll; const int N=50005; int n; int dp[N],dn[N]; struct node { int v; int id; bool operator < (const node &b)const { if(v==b.v) return id>b.id; return v<b.v; } } a[N]; struct tree { int Max,num; tree() {}; tree(int ma,int nu) { Max=ma; num=nu; } } T[N<<2]; void push_up(int idx) { T[idx].Max=max(T[lc].Max,T[rc].Max); if(T[lc].Max==T[rc].Max) { T[idx].num=(T[lc].num+T[rc].num)%mod; } else { T[idx].num=T[lc].Max>T[rc].Max?T[lc].num:T[rc].num; } } void build(int l,int r,int idx) { if(l==r) { T[idx].Max=0; T[idx].num=0; return; } int mid=(l+r)>>1; build(lson); build(rson); push_up(idx); } void update(int l,int r,int idx,int x,tree y) { if(l==r) { T[idx]=tree {y.Max,y.num}; return; } int mid=(l+r)>>1; if(x<=mid) { update(lson,x,y); } else { update(rson,x,y); } push_up(idx); } tree query(int l,int r,int idx,int x,int y) { if(x<=l&&r<=y) { return T[idx]; } int mid=(l+r)>>1; tree res=tree {0,0}; if(x<=mid) { res=query(lson,x,y); } if(y>mid) { tree t=query(rson,x,y); if(t.Max==res.Max){ res.num+=t.num; res.num%=mod; } else if(t.Max>res.Max) { res=tree {t.Max,t.num}; } } return res; } int main() { freopen("test.in","r",stdin); while(cin>>n) { for(int i=1; i<=n; i++) { scanf("%d",&a[i].v); a[i].id=i; } sort(a+1,a+n+1); build(1,n,1); for(int i=1; i<=n; i++) { tree t=query(1,n,1,1,a[i].id); if(t.Max==0)t.num=1;//前面没有数 t.Max++; update(1,n,1,a[i].id,t); } cout<<T[1].num<<endl; } return 0; }