1. 程式人生 > >[SCOI2009]生日禮物

[SCOI2009]生日禮物

div span 最小 int tag 容易 ons 空間 namespace

這道題很容易看出是一道單調隊列題。

首先我們根據珠子的位置排序。

然後按順序枚舉一個個珠子。

如果該種珠子沒有出現過標記上它的位置,如果出現過修改並打上當前位置。當所有珠子都出現後,將當前位置減去打標記位置最小的一個即為當前解。

可以證明正確性。

顯然選擇珠子越靠後越好。

最小位置的查找要$O(K)$,所以復雜度為$O(NK)$。

這道題$K$比較小,該復雜度能過。但當$K$較大時會超時。

我們充分運用單調隊列的性質,犧牲空間換取時間。

具體做法就是開一個數組記錄第$i$個珠子是否在標記中,然後用一個指針$P$記錄位置最小的珠子。

珠子只會從前往後打上標記,所以當取消珠子的標記時,根據需要向後移動$P$指針直到再一次指向位置最小的珠子即可。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define
LL long long 11 #define inf (1 << 30) 12 13 inline int read() { 14 int w = 0, f = 1; char c = getchar(); 15 while (!isdigit(c)) f = c == - ? -1 : f, c = getchar(); 16 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ 0), c = getchar(); 17 return w * f; 18
} 19 20 const int maxn = 1e6 + 5, maxk = 60 + 5; 21 22 struct Ball { 23 int k, p; 24 } A[maxn]; 25 bool cmp(Ball a, Ball b) { 26 return a.p < b.p; 27 } 28 29 int loc[maxk], N, K, tag[maxn]; 30 31 int main() { 32 N = read(), K = read(); 33 34 int P = 0; 35 rep(i, 1, K) { 36 int T = read(); 37 rep(x, 1, T) A[++P] = (Ball){i, read()}; 38 } 39 sort(A+1, A+N+1, cmp); 40 P = 0; 41 int cnt = 0, ans = (1<<31)-1; 42 memset(tag, 0, sizeof(tag)); 43 rep(i, 1, N) { 44 tag[loc[A[i].k]] = 0; 45 if (!loc[A[i].k]) cnt++; 46 loc[A[i].k] = i; 47 tag[loc[A[i].k]] = 1; 48 while (!tag[P]) P++; 49 if (cnt == K) minn(ans, A[i].p - A[P].p); 50 } 51 printf("%d", ans); 52 return 0; 53 }

[SCOI2009]生日禮物