D. River Locks(思维+简单dp)

D. River Locks

题目大意:

n n n个水槽体积是 v v v, q q q个查询,每次给定注水时间 t i ti ti,问最小需要同时开几个水管,在 t i ti ti前注满所有水槽。(一个水槽注满会向下一个转移时间是0

思路:

时间考虑到 t i ti ti(没什么好说的)
设选了 x x x个水槽,那这 x x x个水槽最好选在 1 − x 1-x 1x。(水满转移不需要时间转移只能向后优先满足左边
那不就是总体积除于 t i ti ti上取整??
是但不完全是!要满足选的前 x x x个水槽在 t i ti ti时刻都已充满,否则就是 − 1 -1 1。(为什么不扩大 x x x这个以后说)
d p [ i ] dp[i] dp[i]记录的是充满前 i i i个水槽的最段时间。
d p [ 1 ] = v [ 1 ] dp[1]=v[1] dp[1]=v[1]
在第 i i i个水槽时,直接在 d p [ i − 1 ] dp[i-1] dp[i1]的时间基础上二分即可。

void work(){
	dp[1]=v[1],sum[1]=v[1];
	for(int i=2;i<=n;i++){
		sum[i]=sum[i-1]+v[i];  // 前缀和
		ll l=dp[i-1],r=1e9;
		while(l<r){
			ll mid=l+r>>1;
			if(mid*i-sum[i-1]>=v[i]) r=mid;  // 前i-1都已满足,余下的水一定可以转移
			else l=mid+1;
		}
		dp[i]=l;
	}
}

不难发现,整个 d p dp dp数组是非严格上升的,故当最小的 x x x不满足时,答案是 − 1 -1 1.

Code

#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
ll n,dp[N],v[N],sum[N];

void work(){
	dp[1]=v[1],sum[1]=v[1];
	for(int i=2;i<=n;i++){
		sum[i]=sum[i-1]+v[i];
		ll l=dp[i-1],r=1e9;
		while(l<r){
			ll mid=l+r>>1;
			if(mid*i-sum[i-1]>=v[i]) r=mid;
			else l=mid+1;
		}
		dp[i]=l;
	}
}

int main(){
guo312;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	work();
	int q; cin>>q;
	while(q--){
		ll ti; cin>>ti;
		ll ans=sum[n]/ti;
		if(sum[n]%ti) ans++;
		if(dp[ans]<=ti&&ans<=n) cout<<ans<<endl;
		else cout<<"-1"<<endl;
	}
	return 0;
}
 

代码 r e re re了???
注意在判断输出时是且运算符,要先判断答案是否小于等于 n n n

AC代码

#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
ll n,dp[N],v[N],sum[N];

void work(){
	dp[1]=v[1],sum[1]=v[1];
	for(int i=2;i<=n;i++){
		sum[i]=sum[i-1]+v[i];
		ll l=dp[i-1],r=1e9;
		while(l<r){
			ll mid=l+r>>1;
			if(mid*i-sum[i-1]>=v[i]) r=mid;
			else l=mid+1;
		}
		dp[i]=l;
	}
}

int main(){
guo312;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	work();
	int q; cin>>q;
	while(q--){
		ll ti; cin>>ti;
		ll ans=sum[n]/ti;
		if(sum[n]%ti) ans++;
		if(ans<=n&&dp[ans]<=ti) cout<<ans<<endl;
		else cout<<"-1"<<endl;
	}
	return 0;
}
 
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要用bug来打败bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值