• 洛谷-P3572 [POI2014]PTA-Little Bird-单调队列优化dp


    题意

    一串数表示树高,从第一棵树开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次跳到最后一棵树最少耗费多少体力。

    基本思路

    典型的单调队列优化$dp$题,$dp$方程为

    $$dp[i]=a[i]<a[min(dp[j].pos)]?dp[j]:dp[j]+1,quad (i-j)<=k$$

    此时可以考虑使用一个长度为$k$的单调队列,队头表示当前消耗体力最小的树,每次新元素判断$dp[i]<dp[q[tail]]$或者 $ dp[i]=dp[q[tail]]&q[tail].height<=i.height $

    此题毒瘤的一点在于卡$STL$的常数,会$TLE$两个点。

    单调队列优化几点要素:

    1. 掐头(存区间最优值)
    2. 去尾(存可能最优值,若将来也一定不会最优的就去掉)
    3. 如果一个选手比你小,还比你强,你就可以退役了 

    $STL$版本

     1 #include<bits/stdc++.h>
     2 #define FOR(i,a,b) for(int i=a;i<b;i++)
     3 #define FOR2(i,a,b) for(int i=a;i<=b;i++)
     4 #define sync ios::sync_with_stdio(false);cin.tie(0) 
     5 #define ll long long
     6 #define INF  0x7f7f7f7f;
     7 #define freopenin(a) freopen(a,"r",stdin);
     8 #define freopenout(a) freopen(a,"w",stdout);
     9 #define MAXN 1000100
    10 #define MOD 10007
    11 using namespace std;
    12 typedef struct{
    13     int val,pos;
    14 }NODE;NODE arr[MAXN];
    15 int dp[MAXN];//单调队列优化的是dp,维护前k个最小的dp 
    16 int n,m;
    17 int main()
    18 {
    19     scanf("%d",&n);
    20     FOR(i,0,n)scanf("%d",&arr[i].val),arr[i].pos=i;
    21     scanf("%d",&m);
    22     FOR(i,0,m)
    23     {
    24         int k;scanf("%d",&k);
    25         deque<NODE>q;//保留最高的点 
    26         //memset(dp,0,sizeof(dp));
    27         dp[0]=0;q.push_back(arr[0]);
    28         for(int i=1;i<n;i++)
    29         {
    30             while(!q.empty()&&q.front().pos+k<i) q.pop_front();
    31             if(!q.empty()&&q.front().val>arr[i].val)dp[i]=dp[q.front().pos];//不消耗体力
    32             else dp[i]=dp[q.front().pos]+1;
    33             while(!q.empty()&&(dp[q.back().pos]>dp[i]||(dp[q.back().pos]==dp[i]&&q.back().val<=arr[i].val)))
    34             q.pop_back();
    35             q.push_back(arr[i]);
    36             //cout<<dp[i]<<" ";
    37         }
    38         printf("%d
    ",dp[n-1]);
    39         
    40     }
    41     return 0;
    42 } 
    View Code

    数组+指针版本

     1 #include<cstdio>
     2 #include<cstring>
     3 #define FOR(i,a,b) for(int i=a;i<b;i++)
     4 #define FOR2(i,a,b) for(int i=a;i<=b;i++)
     5 #define sync ios::sync_with_stdio(false);cin.tie(0) 
     6 #define ll long long
     7 #define INF  0x7f7f7f7f;
     8 #define freopenin(a) freopen(a,"r",stdin);
     9 #define freopenout(a) freopen(a,"w",stdout);
    10 #define sf(a) scanf("%d",&a)
    11 #define pf(a) printf("%d
    ",a)
    12 #define sf2(a,b) scanf("%d%d",&a,&b)
    13 #define MAXN 1000100
    14 #define MOD 10007 
    15 using namespace std;
    16 int arr[MAXN],q[MAXN],n,m,k,dp[MAXN];
    17 int main()
    18 {
    19     sf(n);
    20     FOR(i,0,n)sf(arr[i]);
    21     sf(m);
    22     FOR(i,0,m)
    23     {
    24         sf(k);int head=0,tail=0;
    25         memset(dp,0,sizeof(dp));
    26         dp[0]=0;q[tail]=0;
    27         FOR(j,1,n)
    28         {//dp
    29             while(head<=tail&&(q[head]+k<j))head++;//掐头 
    30             if(arr[q[head]]>arr[j])dp[j]=dp[q[head]];
    31             else dp[j]=dp[q[head]]+1;//计算当前值 
    32             while(head<=tail&&(dp[q[tail]]>dp[j]||(dp[q[tail]]==dp[j]&&arr[q[tail]]<=arr[j])))
    33             tail--;//去尾+如果一个选手比你小,还比你强,你就可以退役了 
    34             q[++tail]=j;
    35             //pf(dp[j]);
    36         }
    37         pf(dp[n-1]);
    38         
    39     }
    40     return 0;
    41 }
    View Code
  • 相关阅读:
    冷门JS技巧
    JavaScript小技巧整理篇(非常全)
    JS实现标签页切换效果
    MySQL主从配置详解
    mysql主从复制(超简单)
    1.4isAlive()方法
    1.3currentThread()方法
    1.2.4注意Sysyem.out.println与i--
    1.2.3实例变量与线程安全
    1.2.2实现Runnable接口
  • 原文地址:https://www.cnblogs.com/tldr/p/11333328.html
Copyright © 2020-2023  润新知