luogu5010 HMR的LIS III (dp+线段树)
这个东西和最长上升子序列很像
考虑如果已经知道每个位置为开头的LIS长度和个数 f[i],我可以扫一遍 判断这个个数和K的大小,找到第一个长度=len而且个数<K的,这个位置就是要选的 然后K-=个数,len--,再记下来我这次选的是这个位置(以后还要判断当前位置是否在上一个钦定住的范围内),然后接着做
那这玩意怎么求呢,离散化一下 算出每个数能跳到的下一个数的大小的区间 倒着dp 用线段树记以这个权值为开头的最大长度和个数 优化转移就可以了
1 #include<bits/stdc++.h> 2 #define CLR(a,x) memset(a,x,sizeof(a)) 3 using namespace std; 4 typedef long long ll; 5 typedef pair<int,ll> pa; 6 const int maxn=5e5+10; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int N,M,Llim,Rlim,L[maxn],R[maxn],a[maxn],tmp[maxn]; 16 int ans[maxn]; 17 ll K; 18 pa ma[maxn<<2],f[maxn]; 19 20 inline void merge(pa &a,pa b){ 21 if(a.first<b.first) a=b; 22 else if(a.first==b.first){ 23 a.second+=b.second; 24 a.second=min(a.second,(ll)1e13+1); 25 } 26 } 27 28 inline void update(int p){ 29 ma[p]=make_pair(0,0); 30 merge(ma[p],ma[p<<1]);merge(ma[p],ma[p<<1|1]); 31 } 32 33 inline void change(int p,int l,int r,int x,pa y){ 34 if(l==r){ 35 merge(ma[p],y); 36 }else{ 37 int m=l+r>>1; 38 if(x<=m) change(p<<1,l,m,x,y); 39 else change(p<<1|1,m+1,r,x,y); 40 update(p); 41 } 42 } 43 44 inline void query(int p,int l,int r,int x,int y,pa &z){ 45 if(x>y||x>M) return; 46 y=min(y,M); 47 if(x<=l&&r<=y) merge(z,ma[p]); 48 else{ 49 int m=l+r>>1; 50 if(x<=m) query(p<<1,l,m,x,y,z); 51 if(y>=m+1) query(p<<1|1,m+1,r,x,y,z); 52 } 53 } 54 55 int main(){ 56 //freopen("","r",stdin); 57 int i,j,k; 58 N=rd(),K=rd(),Llim=rd(),Rlim=rd(); 59 for(i=1;i<=N;i++) 60 a[i]=tmp[i]=rd(); 61 sort(tmp+1,tmp+N+1);M=unique(tmp+1,tmp+N+1)-tmp-1; 62 for(i=1;i<=N;i++){ 63 L[i]=upper_bound(tmp+1,tmp+M+1,a[i]+Llim)-tmp; 64 R[i]=lower_bound(tmp+1,tmp+M+1,a[i]+Rlim)-tmp-1; 65 a[i]=lower_bound(tmp+1,tmp+M+1,a[i])-tmp; 66 // printf("~%d %d %d %d\n",i,a[i],L[i],R[i]); 67 } 68 for(i=N;i;i--){ 69 pa re=make_pair(0,0); 70 query(1,1,M,L[i],R[i],re); 71 if(re.first>=1) f[i]=make_pair(re.first+1,re.second); 72 else f[i]=make_pair(1,1); 73 change(1,1,M,a[i],f[i]); 74 // printf("%d %d %d %d %d %d %d\n",i,L[i],R[i],f[i].first,f[i].second,re.first,re.second); 75 } 76 int len=0; 77 for(i=1;i<=N;i++) 78 len=max(len,f[i].first); 79 printf("%d\n",len); 80 int lst=-1; 81 for(i=1,j=0;i<=N;i++){ 82 if(f[i].first!=len||(lst!=-1&&(a[i]>R[lst]||a[i]<L[lst]))) continue; 83 if(f[i].second<K) K-=f[i].second; 84 else ans[++j]=i,len--,lst=i; 85 } 86 for(i=1;i<=j;i++) 87 printf("%d ",ans[i]); 88 return 0; 89 }