一本通1742题解
这题就是要求最长上升子序列的长度及其个数
暴力代码:
#include<bits/stdc++.h> #pragma GCC optimize(3) using namespace std; const int N=1e5+100; const long long mod=123456789; int n,type; int R[N],f[N],dp[N]; //f[i]表示长度为i的最长上升子序列的最后一个元素的值 //f[i] long long cnt[N]; inline int find(int l,int r,int x){ while(l<=r) { int mid=l+r>>1; if(f[mid]<x) l=mid+1; else r=mid-1; } return l; } int main() { scanf("%d %d",&n,&type); for(int i=1;i<=n;i++) scanf("%d",&R[i]); int len=1; f[1]=R[1]; for(int i=2;i<=n;i++) { if(R[i]>f[len]){ f[++len]=R[i]; } else{ int k=find(1,len,R[i]); f[k]=R[i]; } } printf("%d\n",len); if(!type){ return 0; }else { for(int i=1;i<=n;i++) dp[i]=cnt[i]=1; for(int i=2;i<=n;i++) for(int j=1;j<i;j++) if(R[j]<R[i]) if(dp[j]==dp[i]) dp[i]=dp[j]+1,cnt[i]=cnt[j]%mod; else if(dp[j]+1==dp[i]) cnt[i]=(cnt[i]+cnt[j])%mod; long long ans=0; for(int i=1;i<=n;i++) if(len==dp[i]) ans=(ans+cnt[i])%mod; printf("%lld",ans%mod); } return 0; }
那么想要优化到 $O(nlogn)$,显然需要数据结构来帮忙。仔细观察状态转移方程,发现这其实是一个二维偏序:$i<j\space and\space a[i]>a[j]$。所以,对于第一维我们排序,第二维用数据结构维护。
我们维护树状数组$f[i]\space and\space t[i]$,因为要保证$a[i]>a[j]$,我们在进行$modify(int\space p,int\space x,int\space y)$操作时,直接将 $a_i$ 作为第一维的 $p$,在 $ask$ 操作时从 $a[i]-1$ 开始就一定保证 $a[j]<a[i]$ ,所以呢,大概的代码是这样:
#include<bits/stdc++.h> using namespace std; const int N=1e5+100; const long long mod=123456789; long long f[N],t[N],a[N],Max,tres,tans; int n,type; inline int lowbit(int i){ return i&(-i); } inline void modify(long long p,long long x,long long y){ for(;p<=Max;p+=lowbit(p)) if(f[p]<x) f[p]=x,t[p]=y; else if(f[p]==x) t[p]=(t[p]+y)%mod; return ; } int main(){ scanf("%d %d",&n,&type); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),Max=max(Max,a[i]); modify(a[1],1,1); for(int i=2;i<=n;i++){ long long ans=0,res=1; for(int j=a[i]-1;j>=1;j-=lowbit(j)) if(f[j]>ans) ans=f[j],res=t[j]; else if(f[j]==ans) res=(res+t[j])%mod; modify(a[i],ans+1,res); } for(int j=Max;j>=1;j-=lowbit(j)) if(f[j]>tans) tans=f[j],tres=t[j]; else if(f[j]==tans) tres=(tres+t[j])%mod; printf("%lld",tans); if(type) printf("\n%lld",tres); return 0; }
技巧应用:对于二位偏序,一维排序,二维数据结构;对于三维偏序,一维排序,二维数据结构,三维cdq分治