[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; }
我爱学习,学习使我快乐