洛谷 P1052 过河

题目传送门

方程很好推,f[当前点]=min{f[能一步到这个点的点]+(1或0)}.30分到手.

但是对于100分做法,长度太长,数组开不起,所以要想办法优化.看到最多一步跳t个距离,所以两个石子的中间可能隔着非常长的一段空区间(对答案没啥用),所以我们就要把这些减掉.

每两个相邻的石子之间减去(kt),使其距离x满足(t leq x_i<2t).

注意:最后我们可能不一定非常准确的跳到l上,所以统计答案要从l~l+t-1中找.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int l,s,t,m,a[101],d[105],k,f[100001],ans = 60000,cs;
bool vis[101000];

inline bool cmp(int whk,int oi) {
	return whk < oi;
}

int main() {
	memset(f,0x3f,sizeof(f));
	scanf("%d%d%d%d",&l,&s,&t,&m);
	for(int i = 1;i <= m; i++)
		scanf("%d",&a[i]);
	sort(a+1,a+m+1,cmp);
 	for(int i = 1;i <= m; i++) {
		d[i] = a[i] - a[i-1];
		d[i] = d[i] % t;
	}
	d[m+1] = l - a[m];
	d[m+1] = d[m+1] % t;
	for(int i = 1;i <= m + 1; i++) {
		if(a[i]-a[i-1] >=t) d[i] += t;
		k = k + d[i];
		vis[k] = 1;
	}
	f[0] = 0;
	vis[k] = 0;
	for(int i = 0;i <= k + t; i++)
		for(int j = max(0,i - t);j <= i - s; j++)
			if(vis[i])
				f[i] = min(f[j] + 1,f[i]);
			else 	
				f[i] = min(f[i],f[j]);
	for(int i = k;i <= k + t; i++)
		ans = min(ans,f[i]);
	printf("%d",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/lipeiyi520/p/13898786.html