POI 2014 little bird
阿新 • • 發佈:2019-02-22
.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 namespacestd; #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