x 是看题解的。
[] CF1055E
题意:给定 $n$ 个点,以及 $m$ 条线段,选择 $s$ 条线段,使得至少被一个线段覆盖的点的坐标从小到大排序后,第 $k$ 大最小,没有则输出 $-1$ 。
二分答案 $k$ ,则现在问题变为了选择 $k$ 个线段使得至少覆盖 $p$ 个点。
按照 $r$ 排序后考虑 $dp$,设 $f_i$ 表示选择 $i$ 的最多点数。
由于直接转移是 $O(m^3)$ 通不过本题,则对于相交与不相交建立线段树维护即可。
时间复杂度 $O(m^2\log^2n)$ 。
貌似可以对于点 $dp$ ,维护每个点最右连续 $1$ 位置。$O(1)$ 转移即可,时间复杂度 $O(m^2\log n)$ 。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<climits> #include<set> #define pii pair<int,int> #define fi first #define se second #define pb push_back #define mp make_pair using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=1501; struct Segment{ int Maxn[MAXN<<2],inf; void clear(){memset(Maxn,-127/3,sizeof(Maxn));inf=Maxn[0];return;} void Modify(int k,int l,int r,int ps,int w){ if(l==r){Maxn[k]=w;return;} int mid=(l+r)>>1; if(ps<=mid) Modify(k<<1,l,mid,ps,w); if(mid<ps) Modify(k<<1|1,mid+1,r,ps,w); Maxn[k]=max(Maxn[k<<1],Maxn[k<<1|1]); return; } int Query(int k,int l,int r,int x,int y){ if(x<=l&&r<=y) return Maxn[k]; int res=inf,mid=(l+r)>>1; if(x<=mid) res=max(res,Query(k<<1,l,mid,x,y)); if(mid<y) res=max(res,Query(k<<1|1,mid+1,r,x,y)); return res; } }S[MAXN]; int N,M,K,kth,A[MAXN],tmp[MAXN],cnt,SS[MAXN]; struct Node{int l,r,len;} F[MAXN],G[MAXN]; int f[MAXN][MAXN],pre[MAXN],Maxn[MAXN][MAXN]; bool cmp(Node x1,Node x2){return x1.len<x2.len;} bool cmp1(Node x1,Node x2){return x1.r<x2.r;} bool check(int xx){ for(int i=1;i<=N;i++) SS[i]=SS[i-1]+(A[i]<=xx); for(int i=0;i<=K;i++) S[i].clear(); memset(f,-127/3,sizeof(f)); memset(Maxn,-127/3,sizeof(Maxn));f[0][0]=0; S[0].Modify(1,0,cnt,0,0); for(int i=0;i<=cnt;i++) Maxn[0][i]=0; int Max=0; for(int i=1;i<=K;i++){ for(int j=1;j<=cnt;j++){ f[i][j]=max(f[i][j],Maxn[i-1][pre[j]]+SS[G[j].r]-SS[G[j].l-1]); if(pre[j]+1<=j-1){ int W=S[i-1].Query(1,0,cnt,pre[j]+1,j-1)+SS[G[j].r]; f[i][j]=max(f[i][j],W); } Maxn[i][j]=max(f[i][j],Maxn[i][j-1]); Max=max(Max,f[i][j]); S[i].Modify(1,0,cnt,j,f[i][j]-SS[G[j].r]); } } return Max>=kth; } int main(){ //freopen("A.in","r",stdin); N=read(),M=read(),K=read(),kth=read(); for(int i=1;i<=N;i++) A[i]=tmp[i]=read(); sort(tmp+1,tmp+N+1); int E=unique(tmp+1,tmp+N+1)-tmp-1; for(int i=1;i<=N;i++) A[i]=lower_bound(tmp+1,tmp+E+1,A[i])-tmp; for(int i=1;i<=M;i++) F[i].l=read(),F[i].r=read(),F[i].len=F[i].r-F[i].l+1; sort(F+1,F+M+1,cmp); for(int i=1;i<=M;i++){ bool ff=1; for(int j=i+1;j<=M;j++) if(F[j].l<=F[i].l&&F[i].r<=F[j].r) {ff=0;break;} if(ff) G[++cnt]=F[i]; }sort(G+1,G+cnt+1,cmp1); int l=1,r=E,res=-1; for(int i=1;i<=cnt;i++) for(int j=0;j<=i-1;j++) if(G[j].r<G[i].l) pre[i]=j; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) res=mid,r=mid-1; else l=mid+1; }if(res==-1) printf("-1\n"); else printf("%d\n",tmp[res]); return 0; }/* 4 3 2 2 3 1 3 2 1 2 2 3 4 4 */