Codeforces Round #659 (B. Koa and the Beach (Easy Version(DP)&Hard Version)

B1. Koa and the Beach (Easy Version)

B1. Koa and the Beach (Easy Version)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
题意:
有n个海域,给出每个海域的初始深度,2*k秒为一个循环,前k秒每秒深度+1,后k秒每秒深度-1,你要游到另一边去,每秒可以游到下一个海域或者停留在当前海域,如果当前海域深度大于l,你就会淹死。问你是否能游到另一边。
方法:
DP
f[i][j]代表j秒时是否能到达i海域的状态;
f[i][j]可以从f[i][j-1]或者f[i-1][j-1]两个状态过来;

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110;
int p[2*N],a[N],f[N][2*N*N];
int n,k,l;
void init(int k){
	for(int i=0;i<=k;i++) p[i]=i;
	for(int i=1;i<k;i++) p[i+k]=k-i;
	for(int j=0;j<2*k*n;j++) f[0][j]=1;
}
int main()
{
	int t;
	cin>>t;
	while(t--){
		memset(f,0,sizeof f);
		cin>>n>>k>>l;
		for(int i=1;i<=n;i++) cin>>a[i];
		init(k);
		for(int i=1;i<=n;i++)
		for(int j=i;j<=2*k*n;j++){
			f[i][j]=max(f[i][j-1],f[i-1][j-1]);
			if(p[j%(2*k)]+a[i]>l) f[i][j]=0;
		}
		bool ok=false;
		for(int j=n;j<=2*k*n;j++)
		if(f[n][j]) {ok=true;break;}
		if(ok) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

B2. Koa and the Beach (Hard Version)

B2. Koa and the Beach (Hard Version)
题解:
贪心做法,我们考虑两个完全安全的点的状态,什么是完全安全的点呢?比如a[i] + k <= l,就是加上潮汐的最大增量也不会超过淹死的深度的点。考虑两个完全安全点之间的点,我们思考什么样的贪心决策最好。从一个完全安全点开始,我们不错的决策是,等到潮汐上涨到最大的时候,我们才往之后的点游下去,因为之后潮汐是随着时间下降的,这时候计算tide+a[j]-l的差值,这个差值即为最少需要停留的时间用tide减去即为当前潮汐状态,如果为负数则说明不用停留了。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=300100;
int n,k,l;
int a[N];
int main()
{
	int t;
	cin>>t;
	while(t--){
	cin>>n>>k>>l;
	vector<int> q;//确定安全点
	q.push_back(0); //初始位置也是安全点 
	for(int i=1;i<=n;i++){
		cin>>a[i];
	    if(l-a[i]>=k) q.push_back(i); 
		}
	q.push_back(n+1);//结束位置也是安全点 
	bool ok=true; 
	for(int i=1;i<q.size();i++){
	 bool down=true;int tide=k;//初始状态默认为潮汐下降 
	for(int j=q[i-1]+1;j<q[i];j++){
		tide+=down?-1:1; 
		if(down) tide-=max(tide+a[j]-l,0);
//tide+a[j]-l的意思是最少还需要停留几秒使得tide+a[j]<=l; 
		if(tide<0||tide+a[j]>l)  {ok=false;break;}
//tide<0说明超过潮汐下降的极限,tide+a[j]>l说明潮汐上升到该点已经溺死 
		if(tide==0) down=false;  //说明潮汐准备上升 
		} 
		if(!ok) break;
		}
		if(ok) cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Think-killer

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

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

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

打赏作者

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

抵扣说明:

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

余额充值