http://www.elijahqi.win/archives/3108
题目描述
给定一个只包含整数的序列(序列元素的绝对值大小不超过10^9),你需要计算上升子序列的个数,满足如下条件的称之为一个上升子序列:
是原序列的一个子序列
长度至少为2
所有元素都严格递增
如果两个上升子序列相同,那么只需要计算一次。例如:序列{1,2,3,3}有4个上升子序列,分别为{1,2}{1,3},{1,2,3},{2,3}
输入输出格式
输入格式:
输入的第一行是一个整数n,表示序列长度。接下来一行是n个整数,表示序列。
输出格式:
输出仅包含一行,即原序列有多少个上升子序列。由于答案可能非常大,你只需要输出答案模10^9+7的余数。
输入输出样例
输入样例#1: 复制
4
1 2 3 3
输出样例#1: 复制
4
说明
数据范围
对于 30% 的数据,N ≤ 5000
对于 100% 的数据,N ≤ 10^5
设dp[i]表示以a[i]为结尾的上升子序列个数的增量 因为有重复的 (都是+1的)
所以用权值树状数组维护以a[i]的这些dp值 然后每次做的时候要把上几次的减去 (去重)且这个上几次的需要累加
然后最后答案因为都多算了自己所以减去即可
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
const int N=1e5+10;
const int mod=1e9+7;
inline void add(int &x,int v){x=x+v>=mod?x+v-mod:x+v;}
inline void dec(int &x,int v){x=x-v<0?x-v+mod:x-v;}
int n,a[N],a1[N],nn,s[N],last[N],dp[N],ans;
inline void add1(int x,int v){while(x<=nn) add(s[x],v),x+=x&-x;}
inline int query(int x){int tmp=0;while(x) add(tmp,s[x]),x-=x&-x;return tmp;}
int main(){
freopen("bzoj5157.in","r",stdin);
n=read();for (int i=1;i<=n;++i) a[i]=a1[i]=read();
sort(a1+1,a1+n+1);nn=unique(a1+1,a1+n+1)-a1-1;
for (int i=1;i<=n;++i){
a[i]=lower_bound(a1+1,a1+nn+1,a[i])-a1;
add(dp[i],query(a[i]-1)+1);
dec(dp[i],last[a[i]]);
add(ans,dp[i]);add1(a[i],dp[i]);last[a[i]]+=dp[i];
}dec(ans,nn);printf("%d\n",ans);
return 0;
}