[TJOI2014] 上升子序列

    刚刚做的时候一看:这不是个傻逼题吗hhhhh。。。。然后发现写完了过不了样例,仔细一看题:同构的算一种。

    这可咋办啊?

    其实很简单,设f[i] 为 以a[i] 结尾的上升子序列个数,我们考虑当前如果算到 i 了,那么我们需要查询 a[j] < a[i] 且 j < i 的所有 的 f[j] 的和。

    为了避免重复计算,我们只需要保留每个权值的j最大的那个就行了,因为那个 j 肯定可以包含之前的所有答案。

    

    所以我们边计算边维护即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100005,ha=1000000007;
inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
int a[maxn],num[maxn],ky,n,f[maxn],ans,g[maxn],pre[maxn];
inline void update(int x,int y){ for(;x<=ky;x+=x&-x) f[x]=add(f[x],y);}
inline int query(int x){ int an=0; for(;x;x-=x&-x) an=add(an,f[x]); return an;}
int main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",a+i),num[i]=a[i];
	sort(num+1,num+n+1);
	ky=unique(num+1,num+n+1)-num-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(num+1,num+ky+1,a[i])-num;
	
	for(int i=1;i<=n;i++){
		if(pre[a[i]]) update(a[i],ha-pre[a[i]]);
		g[i]=add(query(a[i]-1),1),update(a[i],g[i]);
		pre[a[i]]=g[i];
	}
	
	for(int i=1;i<=ky;i++) if(pre[i]) ans=add(ans,pre[i]-1);
	
	printf("%d\n",ans);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/JYYHH/p/8962836.html