Question
Analysis
这题如果数据范围再小一点的话很明显可以用dp求解,大概就是这样:
bool vis[maxn];//位置i有无石子
int dp[maxn];//到达位置i的最小踩石子数
fill(dp,dp+maxn,INF);//全部初始化为最大
dp[0] = 0;
for(int i = 1 ; i <= L ; ++i){
for(int j = s ; j <= t ; ++j ){
if(i >= j) dp[i] = min(dp[i],dp[i-j]+vis[i]);
}
} 但是L的范围是1e9,直接算会爆内存的,所以就想到了离散化.
通过观察法,如果青蛙位置是X,那如果X+S到X+T位置都有石头那青蛙才可能踩到石头,
所以那些间隔很远的石头完全可以缩短距离,至于缩短多少距离呢,这个时候就灵机一动 偷看大佬的题解 ,就把距离大于 S * T 的石头缩短为 S * T,至于为什么。打个草稿就好了。
如果 S = 5 ,T = 6:
走一步 能走 5 ~ 6 个单位
走两步 能走 10 ~ 12 个单位
走三步 能走 15 ~ 18 个单位
走四步 能走 20 ~ 24 个单位
走五步 能走 25 ~ 30 个单位
走六步 能走 30 ~ 36 个单位
走七步 能走 35 ~ 42 个单位
举例发现距离大于等于 30 单位的位置都可以到达,然后找一下规律(大佬一眼看出)多列几个就发现距离大于S * T的位置都能到达。所以把距离大于 S * T 的石头缩短为 S * T就好因为青蛙可能跳出桥,所以最后的答案要求 缩短距离后的最大位置 + S*T 之间的最小值
吐槽 : 石头的位置居然不是有序的,我在这看了好久能a的代码,最后还是看ac代码才发现要排序
Code
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
#pragma GCC optimize(3)
typedef long long ll;
#define INF 0x3f3f3f3f
const int mod = 1e9+7;
const int maxn = 1e5+5;
#define iss ios::sync_with_stdio(false)
inline ll read(){
ll s = 0, w = 1; char ch = getchar();
while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
ll ston[105],b[105];//b[i]是离散化后的石头位置
bool vis[95*100];
ll dp[95*100];
int main(){
ll l = read();
int s = read(),t = read(),m = read();
for(int i = 1 ; i <= m ;++i){
ston[i] = read();
}
if(s == t){
ll ans = 0;
for(int i = 1 ; i <= m ;++i)
if(ston[i]%s == 0) ++ans;
cout<<ans<<endl;
return 0;
}
sort(ston+1,ston+1+m);
int div = s*t;
for(int i = 1 ; i <= m ; ++i){
int tmp = ston[i]-ston[i-1];
if(tmp>div) tmp = div;//距离大于s*t的改成s*t
b[i] = b[i-1]+tmp;
vis[b[i]] = true;
}
for(int i = 1 ; i <= b[m]+div; ++i) dp[i] = 1e18;
for(int i = 1 ; i <= b[m]+div ; i++){
for(int j = s ; j <= t ; ++j){
if(i >= j){
if(vis[i]) dp[i] = min(dp[i],dp[i-j]+1);
else dp[i] = min(dp[i],dp[i-j]);
}
}
}
ll ans = 1e18;
for(int i = b[m] ; i < b[m]+div ; i ++){
ans = min(dp[i],ans);
}
cout<<ans<<endl;
}
京公网安备 11010502036488号