BZOJ5321 & 洛谷4064 & LOJ2274:[JXOI2017]加法——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5321
https://www.luogu.org/problemnew/show/P4064
我觉得我永远都不会做九条题的原因就是我傻……这个方法是看同机房dalao代码懂的方法,十分的快。
想了很多贪心都错了之后发现我是个傻子。
”最小值最大“上二分答案,然后我们就知道了每个结点应该被覆盖多少次。
然后一个显然的贪心:从左到右扫结点,覆盖显然越少越好,必须覆盖的时候每次覆盖选择最大的区间。
我们直接对区间排序之后用一个堆维护就行了?
然后记录每个结点被覆盖的情况,直接差分就行了。
(我最开始贪心错了就是因为没有考虑前面已经过去的区间仍然可以覆盖后面的点……)
(突然想到我原贪心改改可能也能过?不过那样代码就奇慢了……)
#include<map> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int INF=1e9; const int N=2e5+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int l,r; }b[N]; int n,m,k,w,a[N]; ll c[N]; priority_queue<int>q; inline bool cmp(node a,node b){ return a.l==b.l?a.r<b.r:a.l<b.l; } bool pan(ll p){ int cnt=0; for(int i=1;i<=n;i++)c[i]=0; while(!q.empty())q.pop(); for(int i=1,j=1;i<=n;i++){ while(j<=m&&b[j].l<=i)q.push(b[j++].r); c[i]+=c[i-1]; while(!q.empty()&&c[i]+a[i]<p&&cnt<k){ if(q.top()>=i)c[i]+=w,c[q.top()+1]-=w,cnt++; q.pop(); } if(c[i]+a[i]<p)return 0; } return 1; } int main(){ int t=read(); while(t--){ n=read(),m=read(),k=read(),w=read(); ll l=INF,r; for(int i=1;i<=n;i++)a[i]=read(),l=min(l,(ll)a[i]); r=l+(ll)w*k; for(int i=1;i<=m;i++)b[i].l=read(),b[i].r=read(); sort(b+1,b+m+1,cmp); while(l<r){ int mid=(l+r+1)>>1; if(pan(mid))l=mid; else r=mid-1; } printf("%d\n",l); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++