题解——额外的体力(单调队列优化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;
}