BOJ 9623 - 부분 수열의 길이

image.png

결국 어떠한 연속된 구간의 합은 S[i]=k=0iA[k]S[i]=\sum_{k=0}^i A[k] 라 할 때,

S[i]S[j] (j<i)S[i]-S[j]~(j < i) 이다.

S[i]S[i] 를 계속 가지고가면, S[i]S[j]XS[i]-S[j] \ge X를 만족하려면 S[i]XS[j]S[i]-X \ge S[j] 여야 한다.

그럼 현재까지 본 S[j]S[j] 중, S[i]XS[i]-X 이하인 jj 중 가장 큰 jj를 구하는 문제가 된다.

세그먼트 트리 풀이가 생각나서 바로 풀었는데, S[j]S[j] 를 인덱스로 가지고 값을 jj 로 가지게끔 해서 S[i]X-\infty \sim S[i]-X 까지 범위에서 가장 큰 인덱스를 찾아오면 된다.

이렇게 쿼리하고 정답을 갱신해준 뒤에 (S[i],i)(S[i], i) 를 트리에 업데이트해준다.

세그 트리를 쓰면 좌표압축을 하거나 다이나믹 세그먼트 트리를 써야해서 구현이 까다로울 수 있다.

const int inf = 2e16;  
// Maximum Value Dynamic Segment Tree  
struct node {  
   int v = -inf, l = -1, r = -1;  
};  
  
struct dynamic_seg_tree {  
   int N, nxt = 1;  
   vector<node> tree;  
   dynamic_seg_tree(int N) : N(N) {  
      tree.pb({});  
   }  
  
   void update(int n, int nl, int nr, int i, int v) {  
      if (nr < i || nl > i) return;  
      if (nl == nr) {  
         tree[n].v = v;  
         return;  
      }  
      int m = (nl + nr) / 2;  
      if (i <= m) {  
         if (tree[n].l == -1) {  
            tree[n].l = nxt++;  
            tree.pb({});  
         }  
         update(tree[n].l, nl, m, i, v);  
      } else {  
         if (tree[n].r == -1) {  
            tree[n].r = nxt++;  
            tree.pb({});  
         }  
         update(tree[n].r, m + 1, nr, i, v);  
      }  
      tree[n].v = max(~tree[n].l ? tree[tree[n].l].v : -inf, ~tree[n].r ? tree[tree[n].r].v : -inf);  
   }  
   void update(int i, int v) {  
      update(0, 0, N - 1, i, v);  
   }  
  
   int query(int n, int nl, int nr, int l, int r) {  
      if (n == -1 || nr < l || nl > r) return -inf;  
      if (nl >= l && nr <= r) return tree[n].v;  
      int m = (nl + nr) / 2;  
      return max(query(tree[n].l, nl, m, l, r), query(tree[n].r, m + 1, nr, l, r));  
   }  
   int query(int l, int r) {  
      return query(0, 0, N - 1, l, r);  
   }  
};  
  
void solve() {  
   int n, x;  
   cin >> n >> x;  
   vi a(n);  
   fv(a);  
   dynamic_seg_tree seg(inf);  
   int sum = 0;  
   seg.update(inf / 2, 0);  
   int ans = inf;  
   for (int i = 0; i < n; i++) {  
      sum += a[i];  
      int ret = seg.query(0, sum - x + inf / 2);  
      if (ret != -inf) ans = min(ans, i - ret + 1);  
      seg.update(sum + inf / 2, i + 1);  
   }  
   cout << (ans == inf ? -1 : ans) << endl;  
}

Tags:

Categories:

Updated:

Comments