Vijos 1002 过河 dp + 思维

https://www.vijos.org/p/1002

设dp[i]表示跳到了第i个点,需要的最小的步数。

所以复杂度O(L * T), 不行

注意到T最大是10, 所以dp[i]最多只由10项递推过来。

考虑上面的那个情况,如果两个相邻的石头距离大于10,那么其实是没意义的,比如上面那两个空的10的位置,完全是可以省略的。因为它相当于从那个有石子的那10个转移过来。所以只要两个距离大于10的石子,就可以压缩距离是10即可。

但是这样做的话,有一个大前提,就是你必须保证每个位置都是可达的。否则,比如你只能去到18和19,你就不能把这两个位置压缩成10和11,因为很有可能10和11是不可达的状态,然后你这个石子就永远枚举不了。也破坏了整到题目的题意。

所以只有保证每个状态都是可达的,然后又是空的位置,才能省略。

最差情况是s == t,这个时候特判。

然后就是s + 1 == t,比如9、10的时候,可达的地方是:

0、9、10、18、19、20、27、28、29、30......观察到大于100后,全部状态都是可达的,所以这个时候就可以压缩了。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 1e5 + 20;
int a[maxn], dp[maxn];
int f[maxn];
void work() {
    memset(dp, 0x3f, sizeof dp);
    int L, s, t, m;
    scanf("%d%d%d%d", &L, &s, &t, &m);
    for (int i = 1; i <= m; ++i) {
        scanf("%d", f + i);
    }
    sort(f + 1, f + 1 + m);
    int to = 0;
    for (int i = 1; i <= m; ++i) {
        if (f[i] - f[i - 1] > 100) {
            to += 100;
            a[to] = true;
        } else {
            to += f[i] - f[i - 1];
            a[to] = true;
        }
    }
    if (s == t) {
        int ans = 0;
        for (int i = 1; i <= m; ++i) {
            ans += f[i] % s == 0;
        }
        cout << ans << endl;
        return;
    }
    dp[0] = 0;
    for (int i = s; i <= maxn - 20; ++i) {
        int be = max(0, i - t), en = max(0, i - s);
        for (int j = be; j <= en; ++j) {
            dp[i] = min(dp[i], dp[j] + a[i]);
        }
    }
    int ans = inf;
    for (int i = maxn - 20; i <= maxn - 1; ++i) {
        ans = min(ans, dp[i]);
    }
    cout << ans << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}

时间: 2024-12-29 10:17:05

Vijos 1002 过河 dp + 思维的相关文章

vijos 1002过河[单调dp,滚动数组,离散化]

这道题是NOIP第一道DP优化题,看似容易,实际上想要满分也颇有难度. 传送门:1002 过河 算法 此题显然要用到DP,DP方程也显而易见: if (stone[i]) f[i]=min{f[i-j]}+1; (S<=j<=T) else f[i]=min{f[i-j]}; 这样的时间复杂度为 O(LT) ,空间复杂度为 O(L) . 而此题的L高达 10亿 ,所以这种朴素的方法只能得 30分 ,显然无法AC. 优化 1.滚动数组 根据我们得出的DP方程,状态转移只需用到 f[i-T]~f[

vijos 1002 过河

https://www.vijos.org/p/1002 分析:很容易想到f[i]=min(f[i],f[i-j]+is_stone[i])的递推式,但L高达10^9,很明显会TLE,我们发现m<= 100,在长达1到10^9的线段里就只有100个点这是多么的稀疏,我们看看有什么方法压缩一下,引用: 问题的关键就是多么长的空地才能保证青蛙对这些空地是处处可达的?假设这个距离是X,那么比X长的空地也都是处处可达的,就与长为X的空地等效了,因此这就是压缩长度的关键.最后的结论是X=T^2.青蛙跳跃X

Vijos P1002 过河 (NOIP提高组2005)

链接:https://www.vijos.org/p/1002 解析: 若 p*x+(p+1)*y=Q(采用跳跃距离p和p+1时可以跳至任何位置Q),则在Q ≥ P*(P-1)时是一定有解的. 由于题目给出的一个区间是1≤S≤T≤10,于是当相邻的两个石子之间的距离不小于8*9=72时,则后面的距离都可以到达,我们就可以认为它们之间的距离就是72.如此一来,我们就将原题L的范围缩小为了100*72=7200,动态规划算法完全可以承受了. 但是当S=T时,上述等式是无法使用的,在这种情况下,只需要

vijos p1002——过河(noip2005提高组T2)

描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥. 题目给出独木桥的长度L,青蛙跳跃的距离范围

Vijos 1180 (树形DP+背包)

题目链接: https://vijos.org/p/1180 题目大意:选课.只有根课选了才能选子课,给定选课数m, 问最大学分多少. 解题思路: 树形背包.cost=1. 且有个虚根0,取这个虚根也要cost,所以最后的结果是dp[0][m+1]. 本题是cost=1的特殊背包问题,在两个for循环上有一个优化. for(f+1...j....cost) for(1....k...j-cost) 其中f为当前已经dfs子结点个数.之所以+1,是因为根要预留一个空间. f+=dfs(t),dfs

NOIP2005过河[DP 状态压缩]

题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥. 题目给出独木桥的长度L,青蛙跳跃的距离

袋鼠过河---DP

题目:一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子,每隔一米就有一个,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳的更远,每个弹簧力量不同,用一个数字代表它的力量,如果弹簧力量为5,就代表袋鼠下一跳最多能够跳5米,如果为0,就会陷进去无法继续跳跃,河流一共N米宽,袋鼠初始位置就在第一个弹簧上面,要跳到最后一个弹簧之后就算过河了,给定每个弹簧的力量,求袋鼠最少需要多少跳能够到达对岸.如果无法到达输出-1: 输入:输入分两行,第一行是数组长度N,第二行是每一项的值,用空格分隔: 输

ooj 1066 青蛙过河DP

http://121.249.217.157/JudgeOnline/problem.php?id=1066 1066: 青蛙过河 时间限制: 1 Sec  内存限制: 64 MB提交: 58  解决: 13[提交][状态][讨论版] 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上. 由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整数: 0,1,……,L(其中L是桥的长度). 坐标

Vijos 1100 (区间DP)

题目链接: https://vijos.org/p/1100 题目大意:NOIP著名的加分二叉树.给出一棵树的中序遍历,加分规则左子树*右子树+根.空子树分数为1.问最大加分的树结构,输出树结构的先序遍历. 解题思路: 先从小的问题看起. 对于一棵子树,只要知道根是啥,就能轻松求出这棵子树的加分情况. 那么就变成枚举根的区间DP问题. 由于要输出先序遍历,则用m[i][j]记录在i~j区间选择的根. 区间DP边界: ①一个点情况:即无左右子树,dp[i][i]=node[i],m[i][i]=i