Luogu P1052 过河
思路
动态规划不用说,而且这道题的转移方程非常简单,连我都能推出来。难就难在怎么去优化空间和时间。因为$\large{L\le 10^9}$,直接开数组的话不仅空间会炸的连渣都不剩,而且枚举的时候时间也会炸的连渣都不剩。看了题解后,我感到了世界对我的恶意我好弱鸡。用离散化的方法缩小复杂度。
输入之后将石头的位置排序。首先保证它们是递增的,那么相邻的两个石头之间肯定没有其他石头了。所以相邻的两个石头坑定能通过$\large{tx+(a[i]-a[i-1])\%t}$走出来,但是我们根本不用考虑x,直接看做$1$,那么数组的大小数组的大小就变成了$\large{2*t*m}$。明显的小了不少。
状态转移方程
$$\large{dp[i] = min(dp[i], dp[i-j]+flag[i-j]), s\le j\le t}$$
代码
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; int m, L, s, t, dp[2500], a[105], cnt, ans = 2147483647; bool flag[2500]; int main() { scanf("%d%d%d%d", &L, &s, &t, &m); memset(dp, 0x3f, sizeof(dp)); for(int i=1; i<=m; i++) { scanf("%d", &a[i]); } a[m+1] = L; sort(a, a+2+m); for(int i=1; i<=m+1; i++) { if(a[i] - a[i-1] > t) cnt += (a[i]-a[i-1]) % t + t; else cnt += a[i]-a[i-1]; flag[cnt] = true; } flag[cnt] = 0, flag[0] = 0, dp[0] = 0; for(int i=1; i<=cnt+t+1; i++) { for(int j=s; j<=t && i-j>=0; j++) { dp[i] = min(dp[i], dp[i-j]+flag[i-j]); } } for(int i=cnt; i<=cnt+t; i++) { ans = min(dp[i], ans); } printf("%d", ans); }
作者:Mystical-W
来源:http://www.cnblogs.com/bljfy
说明:客官~~您如果觉得写得好的话,记得给我点赞哦。如果要转载的请在合适的地方注明出处。谢
谢您的合作。您要是有什么有疑问的地方可以在下面给我评论。也可以直接私信我哦
声明:本作品由Mystical-W采用知识共享署名-非商业性使用-禁止演绎 4.0 国
际许可协议进行许可
来源:http://www.cnblogs.com/bljfy
说明:客官~~您如果觉得写得好的话,记得给我点赞哦。如果要转载的请在合适的地方注明出处。谢
谢您的合作。您要是有什么有疑问的地方可以在下面给我评论。也可以直接私信我哦
声明:本作品由Mystical-W采用知识共享署名-非商业性使用-禁止演绎 4.0 国
际许可协议进行许可