题解——额外的体力(单调队列优化DP)

题解——额外的体力(单调队列优化DP)

这就是道模板题,然而ssw02考场单调队列写挂了(ssw02是真的菜)
明天还有学长的ACM赛制比赛,幸好有 tqr06 组队。


题面

现在你所的旅行团将要走一段路 ,具体来说,这条路被分成了 N段,每一段都有个凸出程度ai。
这个旅行团有 T个人,每个有一最大步 幅 Ki,也就是说若当前你在 ,也就是说若当前你在 ,也就是说若当前你在 x段,下一次你最多走到x +Ki段
当一个人走下坡路时, 走下坡路时这个人将自在的通过,反之将消耗1点额外的体力。
问每个人最少消耗的体力 。

每次可以在前K段中找。单调队列优化后时间就可以过。
主要提一下:
在排序的时候,以消耗体力作为第一关键字,维护单调递增,再以高度作为第二关键字,维护单调递减。

AC代码1(ssw02)

#include<bits/stdc++.h>
using namespace std;
const  int  N =  2000001 ;
inline int read(){
	int s = 0 ;
	char g = getchar() ;
	while(g>'9'||g<'0')g=getchar() ;
	while(g>='0'&&g<='9')s=s*10+g-'0', g = getchar() ;
	return s ;
}  
int  n , T , k , a[ N ] , loc[ N ], q[ N ] , tot = 0   ;
int f[ N ] ;
int main()
{
	freopen("extra.in","r",stdin);
	freopen("extra.out","w",stdout);
    n = read() ;
    for(int i = 1;i <= n ; i++ ) scanf("%d",&a[ i ]);
    T = read() ;
    while( T-- ){
    	k = read() ;
    	int  head = 1 , tail = 0 ;
        memset( q , 0 , sizeof(q));
        memset( loc, 0 , sizeof(loc));
        memset( f , 0 , sizeof(f) ) ; 
        head = 1 , tail = 0 ; tot = 0 ;f[ 1 ] = 0 ;q[++tail] = 0 ;loc[ tail ] = 1 ;
        for( int i = 2 ; i <= n ; i++ ){
            while( head <= tail && i - loc[ head ] > k ) head++ ; //队不为空 且 队首太远 出队
			( a[ loc[head] ]>a[ i ] )?f[ i ]=q[head]:f[ i ]=q[head]+1 ;
            while( 1 ){//这里写得太麻烦了
            	if( !(head <= tail ) || f[ i ] > q[ tail ] )break ;
            	if( f[ i ]==q[ tail ]&&a[ i ]<=a[ loc[ tail ] ])break ; 
            	if( head <= tail && a[ i ] > a[ loc[tail] ] && f[ i ] == q[ tail ] )tail--;
            	if( head <= tail && f[ i ] < q[ tail ] )tail-- ;
            }//清队尾 
			q[ ++tail ] = f[ i ] ; loc[ tail ] = i ; //将新元素入队
        }
        //for( register int i = 1 ; i <= n ; ++i )printf("%d ",f[i] ) ;
        printf("%d\n",f[ n ]) ;
    }
    return 0;
}

优美的std

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define dnt long long 
#define inf 0x3f3f3f3f

const int N = 1e6 + 11;

int n, K, f[N], q[N], hd = 1, tl = 0, a[N];

int main() {
	cin>>n;
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int T; cin>>T;
	while( T -- ) {
		scanf("%d", &K); memset(f, inf, sizeof(f));
		hd = 1, tl = 0;
		f[1] = 0; q[++tl] = 1;
		for(int i = 2; i <= n; i++) {
			while(hd <= tl && q[hd] + K < i) ++ hd;
			f[i] = f[q[hd]] + ((a[q[hd]] <= a[i]) ? 1 : 0);
			while((hd <= tl) && ((f[q[tl]] > f[i]) || ((f[q[tl]] == f[i]) &&( a[q[tl]] < a[i]))))--tl;
			q[++tl] = i;
		}
		printf("%d\n", f[n]);
	}
	return 0;
}

有疑惑和建议,可以留下评论或私我。(这道题就是个板子)

如果你喜欢我的文章,请点赞支持,谢谢。

posted @ 2019-07-19 21:21  蓝银杏-SSW  阅读(219)  评论(0编辑  收藏  举报
//结束