题解:P11296 [NOISG2018 Prelim] Snail

题目链接

分析

很巧妙的一道题,细节也很多。
事先说明:\(h\)\(p\)\(n\) 与题目意思相同,\(sum\) 表示每天总位移。
不妨考虑下面情况:

5 2
6 -4

此时为直接枚举每天爬行。

注意:不能通过计算 \(sum\) 通过直接 \(h \div sum\) 来计算天数。
因为在这种情况下,可能因为先前爬出去了后面又退回来。

那如何解决呢?

不妨通过枚举前 \(2\) 天的位移,在这里我们定义 \(i\) 为第 \(i\) 个阶段(总的)
\(mn[i]\) 来表示在第 \(i\) 天前的总位移。
那么我们可以推出

\[mn[i+1]=mn[i] + p[i] \]

但此时要注意 \(p[i]\) 有可能为负,倒退回原点甚至更远,且 \(0 \le i < 2 \times n\)
所以应该改为

\[mn[i+1] = \max(mn[i]+p[i],0) \]

接下来就是简单的模拟实现了。

实现

具体内容都在注释,不过多赘述。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=9223372036854775807;
ll h,n,p[10005],sum,mn[20005];
int main(){
	cin>>h>>n;
	for(int i=0;i<n;i++){
		cin>>p[i];
		sum+=p[i];//统计一天内总位移
	}
	//mn[i]指在第i次操作时之前的总位移 
	for(int i=0;i<2*n;i++){//枚举前两天的操作数 
		mn[i+1]=max(mn[i]+p[i%n],0LL);//第i+1次操作时之前的总位移 
		if(mn[i+1]>=h){
			cout<<i/n<<' '<<i%n;//第i/n天,第i%n阶段
			return 0; 
		} 
	}
  //在此时判断是否一天的位移为负数
  //因为会出现走出去后又走回去导致无法出去的情况
  //而在第一天内就会走出去的情况在46行实现
	if(sum<=0){
		cout<<"-1 -1";
		return 0;
	}
  //模拟爬行
	ll ansday=INF,jieduan=0;
	for(int i=0;i<n;i++){
		ll days=1+(h-mn[n+i+1]+sum-1)/sum;//计算
		if(ansday>days){
			ansday=days;
			jieduan=i;
		}
	}
	cout<<ansday<<' '<<jieduan;
	return 0;
}
posted @ 2025-09-23 21:05  ftzx  阅读(4)  评论(0)    收藏  举报