Блог пользователя Pancake

Автор Pancake, 12 лет назад, По-английски

Hello I'm trying to solve problem SUPPER from SPOJ. I think a number x[n] is defined to be super if length of LIS[n] (longest increasing subsequence ending at x[n]) plus LDC[n] (length of longest decreasing subsequence ending at x[n] , when reading the input permutation in reverse) equals the length of longest increasing subsequence of the entire input permutation . Solution Complexity is O(N log N). I'm using Segment Tree , suppose node n covers interval [i .. j] , then tree[n] = max { LIS [ x [ i ] ] , LIS [ x [ i + 1 ] ] , ... , LIS [ x [ j ] ] }

I used an O(N^2) solution to compare my answers against. Thanks a lot in advance for any help.

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

const int MAXN = 100001;
int N;
int x[MAXN];
int LIS[MAXN];
int LDS[MAXN];
int lis[MAXN];
int lds[MAXN];
int tree[4 * MAXN];
int best;

int query(int node , int s , int e , int qs , int qe){
   if(s > qe || e < qs)
      return 0;
   if(s >= qs && e <= qe)
      return tree[node];
   return max(query(2 * node , s , (s+e)/2 , qs , qe) , query(2 * node + 1 , (s+e)/2+1, e , qs , qe));
}
void update(int node , int s , int e , int idx , int val){
   if(s == e && s == idx){
      tree[node] = val;
      return;
   }
   if(s > idx || e < idx)
      return;
   update(2 * node , s , (s+e)/2 , idx , val);
   update(2 * node + 1 , (s+e)/2 + 1 , e , idx , val);
   tree[node] = max(tree[2 * node] , tree[2 * node + 1]);
   return;
}

int main(){
   scanf("%d" , &N);
   for(int n = 1 ; n <= N ; n++)
      scanf("%d" , &x[n]);
   for(int n = 1 ; n <= N ; n++){
      LIS[n] = 1 + query(1 , 1 , N , 1 , x[n] - 1);
      update(1 , 1 , N , x[n] , LIS[n]);
      best = max(best , LIS[n]);
   }
   memset(tree , 0 , sizeof(tree));
   for(int n = N ; n >= 1 ; n--){
      LDS[n] = 1 + query(1 , 1 , N , x[n] + 1 , N);
      update(1 , 1 , N , x[n] , LDS[n]);
   }
   vector < int > res;
   for(int n = 1 ; n <= N ; n++){
	  // printf("%d %d\n" , LIS[n],LDS[n]);
      if(LIS[n] + LDS[n] - 1 == best)
         res.push_back(x[n]);
   }

   
   /*
   for(int n = 1 ; n <= N ; n++){
       lis[n] = 1;
	   for(int h = 1 ; h < n ; h++)
		   if(x[n] > x[h])
			   lis[n] = max(lis[n] , lis[h] + 1);
   }
   for(int n = N ; n >= 1 ; n--){
       lds[n] = 1;
	   for(int h = N  ; h > n ; h--)
		   if(x[n] < x[h])
		     lds[n] = max(lds[n] , lds[h] + 1);
   }
   printf("\n\n");
   for(int n =  1 ; n <= N ; n++)
	   printf("%d %d\n" , lis[n] , lds[n]);
   
  */

   sort(res.begin() , res.end());
   printf("%d\n" , res.size());
   for(int i = 0 ; i < (int)(res.size()) - 1 ; i++)
      printf("%d " , res[i]);
   printf("%d\n" , res.back());
   return 0;
}

Example test case :

Input : 
25
19 6 7 11 5 9 8 18 14 4 23 1 13 10 25 2 16 3 12 15 21 17 20 22 24 

Output (by both O(N log N) and O(N^2) solutions): 
11
6 7 8 9 10 12 15 17 20 22 24
  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

»
9 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

lol I've just solved that problem and I think you've only over-complicated the task. Do you really need LDC[ x ]? And why do you use a segment tree when it is slower and worse to code than a BIT? After calculating the LIS terminating at every indexyou can just find super numbers in linear time.

Hint: Suppose you're at index i of the array A and you already know that number A[ j ] (where j>i) is a super number. What can you say about A[i], looking at A[i], A[j], Lis[j] and Lis[i] ? Try on paper, I found algorithm in that way :)