zoukankan      html  css  js  c++  java
  • P3957 跳房子

    P3957 跳房子

    祭奠一下逝去的时间


    题解

    50pt Solution

    看到这个题直觉想到是DP 但是不会写

    我们可以二分答案,花费金币为 (mid) ,二分枚举 (mid)

    我们设置 (f[i]) 为到达第 (i) 个节点时的最大得分,由于跳房子是一直往右跳的,所以 (f[i]) 一定是由它之前的节点中得分最大的转移过来的,所以有:

    for(int i=1;i<=n;i++)
    	  for(int j=i-1;j>=0;j--){
    	  	if(x[i]-x[j]>=lef&&x[i]-x[j]<=rig)
    	  	   f[i]=max(f[i],f[j]+s[i]);
            if(f[i]>k) return 1;
    	  }
    

    但是这题数据太大了。。。(n^2) 只能 (50pt)

    (code)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    typedef long long ll;
    
    inline int read()
    {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch<'0'||ch>'9') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    
    const int maxn=5e5+10,inf=-1e9+10;
    int n,d,k;
    int s[maxn],x[maxn];
    int l=0,r=0,mid=0;
    ll f[maxn];
    int ans;
    
    bool check(int mid)
    {
    	for(int i=1;i<=n;i++) f[i]=inf;
    	int lef=max(1,d-mid);
    	int rig=d+mid;
    	for(int i=1;i<=n;i++)
    	  for(int j=i-1;j>=0;j--){
    	  	if(x[i]-x[j]<lef) continue;
    	  	if(x[i]-x[j]>rig) break;
    	  	f[i]=max(f[i],f[j]+s[i]);
    	  	if(f[i]>k) return 1;
    	  }
    	return 0;
    }
    
    int main()
    {
    	n=read();d=read();k=read();
    	for(int i=1;i<=n;i++){
    		x[i]=read();s[i]=read();
    		if(s[i]>0) ans+=s[i];
    		r=max(r,x[i]);
    	}
    	if(ans<k){
    		printf("-1
    ");
    		return 0;
    	}
    	while(l<r){
    		mid=(l+r)>>1;
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	printf("%d
    ",r);
    	
    	return 0;
    }
    

    100pt Solution

    满分要二分+DP+单调队列

    我们又上面可知

    (f[ i ]=max( f[j] )+s[i] ,j<i)

    而且随着 (i) 不断往前跳,向前更新,(j) 一定会有不在弹跳范围内的,所以由单调性可知可以使用单调队列

    队列队首维护使得 $f[i] $ 最大的那个点下标

    我们枚举 (j) ,只需要枚举一遍就行了,(j) 是那个待加入的点的下标,如果它在弹跳范围内,而且下标小于 (i) ,就把它加入到队列中的合适位置,加入之后仍然保持队列单调性,弹出超出合法弹跳区间的点,如果队列非空就更新 $f[i] $ 的值

    主体部分:

    bool check(ll mid)
    {
    	q.clear() ;
    	for(int i=1;i<=n;i++) f[i]=inf;f[0]=0;
    	ll lef=(d-mid<0?1:d-mid);
    	ll rig=d+mid;
    	int j=0;
    	for(int i=1;i<=n;i++){
    		while(x[i]-x[j]>rig) j++;
    		while(x[i]-x[j]<=rig&&x[i]-x[j]>=lef&&j<i){
    			while(!q.empty() &&(f[j]>=f[q.back() ]||x[i]-x[q.back()]>rig)) q.pop_back() ;
    			q.push_back(j) ;
    			j++;
    		}
    		while(!q.empty() &&x[i]-x[q.front() ]>rig) q.pop_front() ;
    		if(!q.empty()) f[i]=f[q.front()]+s[i];
    		if(f[i]>=k) return 1;
    	}
    	return 0;
    }
    
    

    (code)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    typedef long long ll;
    
    inline ll read()
    {
    	ll ans=0;
    	char last=' ',ch=getchar();
    	while(ch<'0'||ch>'9') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    
    const int maxn=5e5+10;
    const ll inf=-1e18+10;
    int n;
    ll k,d;
    ll s[maxn],x[maxn];
    ll l=0,r=0,mid=0;
    ll f[maxn];
    deque<ll>q;
    
    bool check(ll mid)
    {
    	q.clear() ;
    	for(int i=1;i<=n;i++) f[i]=inf;f[0]=0;
    	ll lef=(d-mid<0?1:d-mid);
    	ll rig=d+mid;
    	int j=0;
    	for(int i=1;i<=n;i++){
    		while(x[i]-x[j]>rig) j++;
    		while(x[i]-x[j]<=rig&&x[i]-x[j]>=lef&&j<i){
    			while(!q.empty() &&(f[j]>=f[q.back() ]||x[i]-x[q.back()]>rig)) q.pop_back() ;
    			q.push_back(j) ;
    			j++;
    		}
    		while(!q.empty() &&x[i]-x[q.front() ]>rig) q.pop_front() ;
    		if(!q.empty()) f[i]=f[q.front()]+s[i];
    		if(f[i]>=k) return 1;
    	}
    	return 0;
    }
    
    int main()
    {
    	n=read();d=read();k=read();
    	for(int i=1;i<=n;i++) x[i]=read(),s[i]=read();
        l=0,r=x[n];
        while(l<r){
        	mid=(l+r)>>1;
        	if(check(mid)) r=mid;
        	else l=mid+1;
    	}
    	if(!check(l)) {
    		printf("-1
    ");
    		return 0;
    	}
    	printf("%lld
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    Input:type属性
    HttpServletRequest的方法详细说明
    leetcode 第一题 Two Num java
    python之路
    Elasticsearch template学习
    利用Supervisor来守护我们自己的进程
    安装与使用ansible-Centos6.5
    Elasticsearch的一个清理Index脚本
    用统计模拟的方法分析微信抢红包
    数据挖掘R与SQL
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/12152901.html
Copyright © 2011-2022 走看看