【P3957】跳房子(单调队列+DP+二分)
终于把这个题缸出来了,话说这题也不是想的那么难。。。
因为最小的最大,所以二分,因为由前面推出后面,所以DP,因为输入单调,朴素DP会T,所以单调队列。要注意的是,这个题数据很大,要开LL,然后DP数组每次要清为一个大负值,因为输入中有负值。然后单调队列的使用还是有些清奇的地方,待会看代码吧。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define re register #define ll long long #define mo 2015 using namespace std; long long n,dis,k; long long ans,m,cnt,tot,d[5000001],maxd,cost,l,r,flag,leftt,rightt; long long s[5000001],f[1000001]; ll q[2000001],head,tail; long long maxx; inline bool check(int x) { for(re int i=1;i<=n;i++) f[i]=-1e12; memset(q,0,sizeof(q)); head=1;tail=0; leftt=max(dis-x,(ll)1); rightt=dis+x; int p=0; for(re int i=1;i<=n;i++) { while(d[i]-d[p]>=leftt&&p<i) { while(head<=tail&&f[p]>=f[q[tail]]) tail--; q[++tail]=p; p++; } while(head<=tail&&d[i]-d[q[head]]>dis+x) head++; if(head>tail) continue; f[i]=s[i]+f[q[head]]; if(f[i]>=k) return 1; } return 0; } int main() { cin>>n>>dis>>k; for(re int i=1;i<=n;i++) { cin>>d[i]>>s[i]; } int l=0,r=100000001; while(l<=r) { int mid=l+r>>1; if(check(mid)) { r=mid-1; }else l=mid+1; } cout<<l; return 0; }
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。