题意
给出一个序列,问序列中有多少个本质不同的上升子序列。
n<=100000
n
<=
100000
分析
我的方法好像比较复杂。。。
设f[i]表示以i为结尾且之前没有出现过的上升子序列数量。
考虑转移,设ls[i]表示上一个与i权值相同的位置,那么
f[i]=∑i−1j=ls[i]+1f[j]∗[a[j]<a[i]]
f
[
i
]
=
∑
j
=
l
s
[
i
]
+
1
i
−
1
f
[
j
]
∗
[
a
[
j
]
<
a
[
i
]
]
显然可以用可持久化线段树来优化。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005;
const int MOD=1000000007;
int n,a[N],w[N],tot,rt[N],sz,ls[N],f[N];
struct tree{int s,l,r;}t[N*20];
void ins(int &d,int l,int r,int x,int y)
{
int p=d;d=++sz;t[d]=t[p];(t[d].s+=y)%=MOD;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) ins(t[d].l,l,mid,x,y);
else ins(t[d].r,mid+1,r,x,y);
}
int query(int d,int p,int l,int r,int x,int y)
{
if (l==x&&r==y) return (t[d].s+MOD-t[p].s)%MOD;
int mid=(l+r)/2;
if (y<=mid) return query(t[d].l,t[p].l,l,mid,x,y);
else if (x>mid) return query(t[d].r,t[p].r,mid+1,r,x,y);
else return (query(t[d].l,t[p].l,l,mid,x,mid)+query(t[d].r,t[p].r,mid+1,r,mid+1,y))%MOD;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),w[i]=a[i];
sort(w+1,w+n+1);tot=unique(w+1,w+n+1)-w-1;
for (int i=1;i<=n;i++) a[i]=lower_bound(w+1,w+tot+1,a[i])-w;
int ans=0;
for (int i=1;i<=n;i++)
{
f[i]=query(rt[i-1],rt[ls[a[i]]],0,tot,0,a[i]-1);
if (!ls[a[i]]) f[i]++,(ans+=MOD-1)%=MOD;
(ans+=f[i])%=MOD;
rt[i]=rt[i-1];ins(rt[i],0,tot,a[i],f[i]);
ls[a[i]]=i;
}
printf("%d",ans);
return 0;
}