P3957 [NOIP 2017 普及组] 跳房子
闲聊: \(n^2\) 过百万,暴力碾标算。Click here.
可见本题数据实在太水了,二分边界开小了反而跑过去了。
先判断一下无解的情况:显然应该是所有正得分的和小于 \(k\)。否则我们可以花上接近无限的金币,让这个机器人足够灵活,灵活到它可以只走遍所有得分为正的格子。
接下来考虑有解的情况。
首先有一个很易得的东西:最大得分随花的金币个数单调不降。
(这个很显然吧?对于一个花费金币较少的最大得分,即使金币增加,我们仍然能走原来的路线,当然也有了新的可能更好的路线,所以肯定单调不降)
那我们首先可以二分花费的金币个数。
然后压力给到 check 函数,它需要对于一个给定的范围区间 \([l,r]\) ,其中 \([l,r]\) 指位置 \(x\) 只能跳到 \([x+l,x+r]\) 中有房子的格子,求最大分数。
这个时候我们联想到一个题,题号P1725 ,正是本题去掉二分后的题面,也算是个弱化版。
我们设 \(dp_{i}\) 表示跳到第 \(i\) 个房子的最大得分。状态转移方程很显然,\(dp_{i}=\max\limits_{j=1}^{i-1}{[pos_{i}-r \le pos_{j} \le pos_{i}-l](dp_{j}+a_{i})}\)。
其中 \(pos_{i}\) 表示第 \(i\) 个房子的位置。
因为本题的 \(pos\) 数组是升序输入的,所以我们发现 \(j\) 转移区间的左右端点都单调不降。于是我们可以用单调队列优化这个 \(dp\) 式子。
单调队列的板子题戳这里。
于是我们就可以愉快地切掉这个蓝题了。
代码:
P3957
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<48){
if(c=='-') f=-1;
c=getchar();
}
while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else write(x/10),putchar(x%10+'0');
}
const int N=5e5+5;
const int V=1e9;
const int inf=2e18;
int n,D,sco,dp[N],q[N];
struct Nahida{
int pos,val;
}a[N];
inline bool check(int G){
//类似P1725正解的check函数
for(int i=1;i<=n;i++){
dp[i]=-inf;
}
int fr=1,tl=0;
dp[0]=0;
int dq=-1;
for(int i=1;i<=n;i++){
//警示后人:我这种写法,在加入队列时只判断了加入元素位置的右端点,所以应该先加入后删除,删掉不合法的解
//加入
while(dq+1<i&&a[dq+1].pos<=a[i].pos-max(1ll,D-G)){
dq++;
while(fr<=tl&&dp[q[tl]]<=dp[dq]){
tl--;
}
q[++tl]=dq;
}
//删除
while(fr<=tl&&a[q[fr]].pos<a[i].pos-D-G){
fr++;
}
if(fr>tl){
dp[i]=-inf;
}
else{
dp[i]=dp[q[fr]]+a[i].val;
}
}
for(int i=1;i<=n;i++){
if(dp[i]>=sco){
return 1;
}
}
return 0;
}
inline int erfen(){
//二分花费金币的个数
int l=0,r=V;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)){
r=mid;
}
else{
l=mid+1;
}
}
return l;
}
signed main(){
n=read(),D=read(),sco=read();
int sum=0;//sum需要开long long
for(int i=1;i<=n;i++){
a[i].pos=read(),a[i].val=read();
if(a[i].val>0) sum+=a[i].val;
}
a[0]={0,0};
if(sum<sco){
printf("-1");
return 0;
}
int ans=erfen();
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号