题面
考场
致力于写暴力,求生欲望强烈又极菜的我,终于死在了暴力上。看到此题第一眼就觉得是线段树维护第k大,所以就不想调正解。
是这样的,我先写了1.2.15.16.17五个点。期望得分25
然后我想了一个dp,NM的,空间不够?滚动数组优化一下啊?好OK啊
按效率来说能过除了18.19.20的所有点,也就是17个点,但是我不会输出方案,就是12*4+5*5=73分
woc,这一波赚啊
于是我就开始写,用暴力去拍,结果莫名其妙挂了,改了好多次还是无果,1.5h过去了,我还在和dp死磕,MMP,结果最后也没调对
考完发现是暴力挂了
最后得分31...
纪念我死去的dp
谴责这天杀的暴力
正解
不得不说,我离正解一步之遥。
只是我认定了这绝对是个线段树,所以没有往优先队列上想,其实是一个一眼题【真的菜】
无论是我的暴力还是dp,都在维护Lmax和Rmin,因为最后求的是交集,交集一定会是边界最小的那一部分,所以维护这两个值很显然
于是出题人向你扔了个优先队列,就对于左端点排序,在优先队列中维护右端点,每次加入一个区间的时候,如果优先队列的元素已经到达了m个,就取出首端的元素用它的右端点和当前加入的这个区间的左端点相减尝试更新答案。
如果超过了m个,就将堆顶元素弹出去。相当于用排序,维护Lmax,用堆维护Rmin,而我是用dp在维护这两个,然后emmm,自己把自己写晕了,全场A穿的题啊TAT
值得一提的是STL的bitset黑科技,相当于一个二进制,存状态太好用了。
代码
#include<iostream> #include<cstring> #include<algorithm> #include<bitset> #include<cstdio> #include<queue> using namespace std; #define N 1000100 int n,m,num,siz,ans; struct email { int l,r,id; bool operator <(email b) const{ return r>b.r; } }a[N]; priority_queue<email>q; bitset<N>tmp,vis; bool cmp(email a,email b) { return (a.l==b.l)?(a.r>b.r):(a.l<b.l); } inline void write(int x) { if(x>9)write(x/10); putchar(x%10+'0'); } int main() { scanf("%d%d%d",&num,&n,&m); for(int i=1;i<=n;i++)scanf("%d%d",&a[i].l,&a[i].r),a[i].id=i; sort(a+1,a+1+n,cmp); for(int i=1;i<=m;i++)q.push(a[i]),tmp[a[i].id]=1,siz++; email x=q.top();ans=max(0,x.r-a[m].l);vis=tmp; for(int i=m+1;i<=n;i++) { q.push(a[i]);siz++;tmp[a[i].id]=1; if(siz>m) { email x=q.top();q.pop(); tmp[x.id]=0; siz--; } if(siz==m) { email x=q.top(); int pos=max(0,x.r-a[i].l); if(pos>=ans) ans=pos,vis=tmp; } } write(ans);puts(" "); for(int i=1;i<=n;i++) if(vis[i]) write(i),putchar(' '); return 0; }