zoukankan      html  css  js  c++  java
  • Little Bird

    【题目描述】

    现有N(2 <= N <= 106)棵树,第i棵树的高度为Di(1 <= Di <= 109)。

    雏鸟想要从第1棵树跳到第N棵树,如果雏鸟在第i棵树,那么它可以跳到第i+1、i+2、······、i+K(1 <= K < N)棵树。如果雏鸟跳到一棵不矮于当前树的树,那么它的劳累值会+1,否则不会。

    询问雏鸟所能达成的最小劳累值是多少。

    【输入描述】

    第一行输入一个整数N,表示树的个数;

    第二行输入N个整数,分别表示第i棵树的高度Di

    第三行输入一个整数Q(1 <= Q <= 25),表示K的个数;

    接下来Q行,每行输入一个整数K。

    【输出描述】

    输出Q行,每行包含一个整数,表示雏鸟在此K情况下所能达到的最小劳累值。

    【输入样例】

    9

    4 6 3 6 3 7 2 6 5

    2

    2

    5

    【输出样例】

    2

    1

    普通的O(nmk)DP解法:

    源代码:
    
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int m,n,i[1000001],f[1000001];
    void Solve(int k)
    {
        f[1]=0;
        for (int a=1;a<=n;a++)
          for (int b=a-1;b>=a-k&&b>0;b--)
            if (i[a]<i[b])
              f[a]=min(f[a],f[b]);
            else
              f[a]=min(f[a],f[b]+1);
        printf("%d
    ",f[n]);
    }
    int main()
    {
        scanf("%d",&n);
        for (int a=1;a<=n;a++)
          scanf("%d",&i[a]);
        scanf("%d",&m);
        for (int a=1;a<=m;a++)
        {
            int k;
            scanf("%d",&k);
            memset(f,0x3f,sizeof(f));
            Solve(k);
        }
        return 0;
    }

    单调队列优化的O(nm)解法:

    源代码:
    
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int m,n,k,i[1000001],f[1000001],Q[1000001],head,tail;
    int main() //竟然可以优化到O(n),看来优先队列挺值得学习的。
    {
        scanf("%d",&n);
        for (int a=1;a<=n;a++)
          scanf("%d",&i[a]);
        scanf("%d",&m);
        while (m--)
        {
            head=1; //队头。
            tail=0; //队尾。
            scanf("%d",&k);
            f[1]=0; //开头并不需要花费体力。
            Q[++tail]=1; //Q[]中存储的是树的编号。
            for(int a=2;a<=n;a++) //DP过程。
            {
                if (a-Q[head]>k) //距离>K,故已过期。
                  head++;
                if (i[a]>=i[Q[head]]) //状态转移方程。
                  f[a]=f[Q[head]]+1;
                else
                  f[a]=f[Q[head]];
                while (head<=tail&&f[a]<=f[Q[tail]]) //跳到tail树的代价>a树的代价时。
                {
                    if (f[a]==f[Q[tail]]&&i[a]<i[Q[tail]]) //代价相等取其高。
                      break;
                    tail--; //跳出没有用的节点。
                }
                Q[++tail]=a; //处理完后就可以在合适的地方入队了。
            }
            printf("%d
    ",f[n]);
        }
        return 0;
    }
  • 相关阅读:
    hdu3001 Travelling
    android 对一个合并后的联系人选择编辑,手机屏幕会缓慢变暗后再进入编辑界面的问题
    数组指针与指针数组 函数指针与指针函数
    CF:322D
    QRadioButton类中Toggled()信号的使用方法
    Android---App Widget(四)
    github 坑爹的仓库初始化设置
    Failed to load session “ubuntu” -- 12.04
    Linux下的图形界面——X Window的安装
    用户管理操作示例
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5703724.html
Copyright © 2011-2022 走看看