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;
}