1 5 2 5 3 1 4 1 4 5 3 2
1 1 2 3 3
题意:有一个数列, 一开始这些数都不可用,接下来每次会让一个位置上的数变得可用,求每次操作后可用数的LIS。
思路:前置知识:长度为N的全排列的LIS的期望为sqrt(N),于是可以倒着让这些数变得不可用,如果它不是LIS上的数就对答案没影响,否则就暴力重新nlogn跑LIS。因为LIS的期望长度为sqrt(N),所以删除某一个数,该数是LIS上的数的概率是1/sqrt(N),也就是说期望会有sqrt(N)个数在LIS上,于是我们最多跑sqrt(N)遍暴力,期望复杂度:O(n*sqrt(n)*log(n))。
#include<bits/stdc++.h> using namespace std; const int N = 50050; int arr[N],b[N]={0},len; int k[N],vis[N]={0}; int pre[N]; int if_lis[N],id[N];int Serach(int num,int low,int high) {int mid;while (low<=high) {mid=(low+high)>>1;if (num>=b[mid]) low=mid+1;else high=mid-1;}return low; }void DP(int n) {len=0;b[len]=-1;id[len]=-1;for(int i=1;i<=n;i++){if(!vis[i])continue;if(arr[i]>=b[len]){len++;b[len]=arr[i];id[len]=i;pre[i]=id[len-1];}else{int pos=Serach(arr[i],1,len);b[pos]=arr[i];pre[i]=id[pos-1];id[pos]=i;}}memset(if_lis,0,sizeof(if_lis));int now=id[len];while(now!=-1){if_lis[now]=1;now=pre[now];} }int ans[N]; int main() {int t;scanf("%d",&t);while(t--){int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&arr[i]);for(int i=1;i<=n;i++)scanf("%d",&k[i]);for(int i=1;i<=n;i++)vis[i]=1;DP(n);ans[n]=len;for(int i=n-1;i>=1;i--){vis[k[i+1]]=0;if(!if_lis[k[i+1]]){ans[i]=ans[i+1];continue;}DP(n);ans[i]=len;}for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n ? 'n' : ' ');}return 0; }View Code
转载于:.html
本文发布于:2024-01-31 16:21:36,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170668929529821.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |