1 条题解

  • 0
    @ 2025-8-24 21:51:01

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar by_chance
    还好我拥有不同的宇宙,能治愈所有我偏执的梦。

    搬运于2025-08-24 21:51:01,当前版本为作者最后更新于2023-03-30 22:17:28,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意:长为 nn0101 数列中有 kk11,满足 mm 个条件。每个条件形如 aia_i,bib_i,cic_i,含义如下:

    • ci=0c_i=0 时,区间 [ai,bi][a_i,b_i] 中没有 11
    • ci=1c_i=1 时,区间 [ai,bi][a_i,b_i] 中有 11

    保证初始有解。求所有必定为 11 的位置。

    1n1051 \le n \le 10^50m<1050 \le m \lt 10^51kn1 \le k \le n1aibin1 \le a_i \le b_i \le n


    首先解决简单情况:

    1. 丢掉所有条件给出为 00 的位置。
    2. 如果剩下的可能位置数与总数相同,剩下的所有位置都满足条件。
    3. 如果有某个 ci=1c_i=1 的区间长为 11,这个位置满足条件。
    4. 如果有某两个 ci=1c_i=1 的区间有包含关系,只用考虑小的那个。

    下面来考虑剩下的情形。对所有区间按左端点递增排序,则右端点也递增。

    首先可以贪心求出一组解(不考虑 kk),这只要从左到右扫描所有区间,如果某个区间还没有 11,在其右端点放 11。同时可以求出满足前 ii 个区间所需要的 11 的数目的最小值 fif_i。类似的,可以求出满足后 ii 个区间所需要的 11 的数目的最小值 gig_i

    “某个位置必须是 11”等价于“某个位置是 00 时无解”。只用考虑那些满足 fi=fi1+1f_i = f_{i-1} + 1 的区间 [ai,bi][a_i,b_i] 的右端点,记为 xx。则满足前 ii 个区间的条件需要 fif_i11

    再考虑所有完全在 x1x-1 右侧的区间,设为后 pp 个。假设 xx 不是 11,所以满足前 ii 个区间时不会满足后 pp 个区间中的任何一个。那么无解的充分必要条件就是 fi+gp>kf_i + g_p \gt k

    pp 可以二分求。时间复杂度 O(nlogn)O(n \log n)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int n,k,m,d[N],t,h[N],lst[N],nxt[N],cnt,st[N],top,f[N],g[N],flag;
    struct range{int l,r;}p[N];
    bool operator <(const range &a,const range &b){
    	return a.l!=b.l?a.l<b.l:a.r<b.r;
    }
    int main(){
    	scanf("%d%d%d",&n,&k,&m);
    	for(int i=1,a,b,c;i<=m;i++){
    		scanf("%d%d%d",&a,&b,&c);
    		if(c==0)++d[a],--d[b+1];
    		else{++t;p[t].l=a;p[t].r=b;}
    	}
    	for(int i=1;i<=n;i++){
    		d[i+1]+=d[i];
    		if(!d[i]){lst[i]=nxt[i]=++cnt;h[cnt]=i;}
    	}
    	if(k==cnt){
    		for(int i=1;i<=cnt;i++)printf("%d\n",h[i]);
    		printf("\n");
    		return 0;
    	}
    	for(int i=1;i<=n;i++)if(!lst[i])lst[i]=lst[i-1];
    	for(int i=n;i>=1;i--)if(!nxt[i])nxt[i]=nxt[i+1];
    	for(int i=1;i<=t;i++)p[i].l=nxt[p[i].l],p[i].r=lst[p[i].r];
    	sort(p+1,p+t+1);top=0;
    	for(int i=1;i<=t;i++){
    		if(p[i].l>p[i].r)continue;
    		while(top&&p[st[top]].r>=p[i].r)--top;
    		st[++top]=i;
    	}t=top;
    	for(int i=1;i<=t;i++)p[i]=p[st[i]];
    	int mx=0,mn=1e9;
    	for(int i=1;i<=t;i++){
    		if(p[i].l>mx)f[i]=f[i-1]+1,mx=p[i].r;
    		else f[i]=f[i-1];
    	}
    	for(int i=t;i>=1;i--){
    		if(p[i].r<mn)g[i]=g[i+1]+1,mn=p[i].l;
    		else g[i]=g[i+1];
    	}
    	for(int i=1;i<=t;i++){
    		if(p[i].l==p[i].r){flag=1;printf("%d\n",h[p[i].l]);continue;}
    		if(f[i]!=f[i-1]+1)continue;
    		int pos=t+1,l=i+1,r=t;
    		while(l<=r){
    			int mid=l+r>>1;
    			if(p[mid].l>p[i].r-1)pos=mid,r=mid-1;
    			else l=mid+1;
    		}
    		if(f[i]+g[pos]>k){flag=1;printf("%d\n",h[p[i].r]);}
    	}
    	if(!flag)printf("-1\n");
    	return 0;
    }
    
    • 1

    信息

    ID
    1448
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者