题解
一道难点不在于dp的dp题目。转移公式很简单
for( i = 1->n )
for( step = s ->t )
f[i] = min(self, f[i-step] + v[i])// v[i]:在i处有无石头
我脑子比较抽用的max()来递推的,其实也一样。
但是这条路有 1e9 长,直接下去是肯定超内存又超时的,必须要想办法把无用的路减少点。
有很多办法可以优化,不限于 路径压缩,离散化等。(我都不懂)
看到个比较易懂的,因为步长只在1-10内,其最小公倍数为2520,意思是对2520外的那个点
在此处总是有办法到的。那么就可以把相隔超过2520的石头点间距减少,这样就可以把路长缩短了。
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 800000;
const int INF = -9999999;
int n,m;
int f[N];
int cot[102];
int main(){
int s,t;
cin>>n>>s>>t>>m;
int tot=1;
for(int i=0;i<m;i++){
cin>>cot[tot++];
}
sort(cot+1,cot+1+m);
if(s==t){ // 特例判断
tot=0;
for(int i=1;i<=m;i++)
if(cot[i]%s==0) tot++;
cout<<tot<<endl;
return 0;
}
int dis;
cot[m] = n;
for(int i=1;i<=m+1;i++){ // 压缩距离
dis=cot[i]-cot[i-1];
if(dis>2520){
dis/=2520;
cot[i]-= dis*2520;
}
}
n = cot[m];
cot[m]=0;
int v;
tot=1;
f[0] = 0;
for(int pos = 1; pos<=n+10;pos++){ // dp
if(cot[tot] == pos) { tot++;v=-1;}
else v =0;
f[pos] = INF;
for(int st = s;st<=t;st++){
if(pos-st<0 || f[pos-st]==INF)continue;
f[pos] = max(f[pos],f[pos-st]+v);
}
}
int ans = INF;
for(int p=n;p<n+10;p++){
if(f[p]>ans) ans = f[p];
}
cout<< -ans<<endl;
return 0;
}