zoukankan      html  css  js  c++  java
  • luogu1052 过河

    题目大意

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

    思路

      本题动规不用说,问题在于怎么使路径压缩。

    思路1

      求出一个单位长度$x$,使得青蛙在区间$[1,x]$上从$[1,T]$开始起跳时,总会有一种跳法跳到$x$处。更严谨地说,也就是存在一个序列$K$,使得$x=sum_{i=S}^T iK_i$。我们看看$S,T$取值范围,简单粗暴地想,令$K_i=gcd(1,2,cdots i-1, i+1, cdots 10)$即可。也就是说,$x=mathrm{lcm}(1, 2, cdots, 10)$。所以对每一个间隔模个$x$即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX_LEN = 2100 * 100, MAX_STONE_CNT = 110, Unit = 2050, INF = 0x3f3f3f3f;
    int Delta[MAX_STONE_CNT], F[MAX_LEN], A[MAX_STONE_CNT];
    bool HaveStone[MAX_LEN];
    int Len, S, T, TotStone;
    
    int main()
    {
        scanf("%d%d%d%d", &Len, &S, &T, &TotStone);
        for (int i = 1; i <= TotStone; i++)
            scanf("%d", A + i);
        sort(A + 1, A + TotStone + 1);
        if (S == T)
        {
            int ans = 0;
            for (int i = 1; i <= TotStone; i++)
                ans += (A[i] % T == 0);
            printf("%d
    ", ans);
            return 0;
        }
        for (int i = 1; i <= TotStone; i++)
        {
            Delta[i] = A[i] - A[i - 1];
        }
        Delta[TotStone + 1] = Len - A[TotStone];
        for (int i = 1; i <= TotStone + 1; i++)
            Delta[i] %= Unit;
        int prevP = 0;
        for (int i = 1; i <= TotStone; i++)
            HaveStone[prevP += Delta[i]] = true;
        Len = prevP + Delta[TotStone + 1];
        memset(F, INF, sizeof(F));
        F[0] = 0;
        for (int i = 1; i <= Len; i++)
            for (int j = S; j <= T && j <= i; j++)
                F[i] = min(F[i], F[i - j] + HaveStone[i]);
        int ans = INF;
        for (int i = Len - T; i <= Len; i++)
            ans = min(ans, F[i]);
        printf("%d
    ", ans);
        return 0;
    }
    

    思路二

      求一个区间长度,使得任何大于这个区间长度的位置都可以到达。我们做过《小凯的疑惑》,知道对任意两个互质的数$a,b$,若整数$x>ab$,则总存在整数$k,t$,使得$x=ka+tb$。因为$t, t-1$互质,所以任何大于$t(t-1)$的位置都可到达。所以遇到大于$t(t-1)$的间隔便将其改为$t(t-1)$即可达到压缩效果。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX_LEN = 2100 * 100, MAX_STONE_CNT = 110, INF = 0x3f3f3f3f;
    int A[MAX_STONE_CNT], Delta[MAX_STONE_CNT], F[MAX_LEN];
    bool HaveStone[MAX_LEN];
    int Len, S, T, TotStone, Unit;
    
    int main()
    {
        scanf("%d%d%d%d", &Len, &S, &T, &TotStone);
        Unit = T * (T - 1);
        for (int i = 1; i <= TotStone; i++)
            scanf("%d", A + i);
        sort(A + 1, A + TotStone + 1);
        if (S == T)
        {
            int ans = 0;
            for (int i = 1; i <= TotStone; i++)
                ans += (A[i] % T == 0);
            printf("%d
    ", ans);
            return 0;
        }
        for (int i = 1; i <= TotStone; i++)
        {
            Delta[i] = A[i] - A[i - 1];
        }
        Delta[TotStone + 1] = Len - A[TotStone];
        for (int i = 1; i <= TotStone + 1; i++)
            if (Delta[i] > Unit)
                Delta[i] = Unit;
        int prevP = 0;
        for (int i = 1; i <= TotStone; i++)
            HaveStone[prevP += Delta[i]] = true;
        Len = prevP + Delta[TotStone + 1];
        memset(F, INF, sizeof(F));
        F[0] = 0;
        for (int i = 1; i <= Len; i++)
            for (int j = S; j <= T && j <= i; j++)
                F[i] = min(F[i], F[i - j] + HaveStone[i]);
        int ans = INF;
        for (int i = Len - T; i <= Len; i++)
            ans = min(ans, F[i]);
        printf("%d
    ", ans);
        return 0;
    }
    

      

  • 相关阅读:
    遇到的两个问题
    项目分析(map复习)
    while小问题
    二级指针
    映射文件实现进程通信
    struct {0}初始化
    用boost共享内存实现进程通信的例子
    mongo二维数组操作
    项目分析(channelid是如果产生的)
    string为什么可以写入共享内存
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9542800.html
Copyright © 2011-2022 走看看