1. 程式人生 > >POI 2014 little bird

POI 2014 little bird

.org eof tdi sca scan 我們 memset org return

題目簡介見https://www.luogu.org/problemnew/show/P3572

dp 方程應該很好寫 (a 數組 為 樹的高度)

j + k >= i 且 j < i

a[j] > a[i] 時 f[i] = min (f[i] , f[j]) ;

a[j] <= a[i] 時 f[i] = min (f[i] , f[j] +1 );

但是 復雜度 N^2*q 老爺機 受不了;

只能優化嘍 ;

推斷1 : 如果有 j > k 且 f[j] < f[k] 那麽 j 永遠比 k 優;

此時可以用單調隊列; 執行推斷1

但是 我們還要考慮樹的高度;

推斷2 :當單調隊列中 j > k 且 f[j] == f[k] 且 a[j] > a[k] 那麽j 比 k 更優秀 ;

終上所述 我們維護f非嚴格遞增 , 當f相同時 , 維護a遞減;

代碼:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cstring>
using namespace
std; #define M 1000100 #define ll long long int n , m , f[M] , a[M] , maxn , high , k , q[M] , l , r; bool sf(int p){ for (int i = l ; i <= r ; ++i){ if (a[q[i]] > p && f[q[i]] == f[q[l]]) return true; } return false; } void solve(){ l = r = 1; q[1] = 1; memset(f ,
0x3f , sizeof(f)); f[1] = 0; for (int i = 2 ; i <= n ; ++i){ while (l <= r && q[l] + k < i ) ++l; if (a[q[l]] > a[i]) f[i] = f[q[l]]; else f[i] = f[q[l]] + 1; while (f[i] < f[q[r]] && r >= l) --r; while (f[i] == f[q[r]]){ if (a[i] >= a[q[r]]) --r; else break; } q[++r] = i; } printf ("%d\n" , f[n] ); } int main(){ freopen("c1.in" , "r" , stdin); // freopen("A.out" , "w" , stdout); scanf("%d" , &n); for (int i = 1 ; i <= n ; ++i) scanf("%d" , a + i); scanf("%d" , &m); while (m--){ scanf("%d" , &k); solve(); } return 0; }

POI 2014 little bird