Cod sursa(job #2229968)

Utilizator radustn92Radu Stancu radustn92 Data 8 august 2018 16:59:18
Problema Subsir crescator maximal Scor 100
Compilator java Status done
Runda Arhiva educationala Marime 5.03 kb
import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws Exception {
        InputStream inputStream = new FileInputStream("scmax.in");
        OutputStream outputStream = new FileOutputStream("scmax.out");

        try (InputReader inputReader = new InputReader(inputStream);
            PrintWriter printWriter = new PrintWriter(outputStream)) {
            int N = inputReader.nextInt();
            int[] values = new int[N + 1];
            for (int i = 1; i <= N; i++) {
                values[i] = inputReader.nextInt();
            }

            List<Integer> longestIncreasingSubSeq = Solver.solve(N, values);
            printWriter.println(longestIncreasingSubSeq.size());
            for (Integer entry : longestIncreasingSubSeq) {
                printWriter.print(entry + " ");
            }
        }
    }

    static class Solver {

        public static List<Integer> solve(int N, int[] values) {
            NormalizedArray normalizedArray = new NormalizedArray(values);
            int totalUniqueElems = normalizedArray.getTotalUniqueElems();
            int[] longestSubseqEndingInPos = new int[N + 1];
            BinaryIndexedTree binaryIndexedTree = new BinaryIndexedTree(totalUniqueElems);
            int longestIncreasingSubseqSize = 0;
            for (int pos = 1; pos <= N; pos++) {
                int normalizedPos = normalizedArray.getNormalizedValue(pos);
                int currBestValue = binaryIndexedTree.getMaxFromOneToPos(normalizedPos - 1) + 1;
                longestSubseqEndingInPos[pos] = currBestValue;
                binaryIndexedTree.setPos(normalizedPos, currBestValue);

                longestIncreasingSubseqSize = Math.max(longestIncreasingSubseqSize, currBestValue);
            }

            List<Integer> solution = new ArrayList<>(N);
            for (int pos = N; pos >= 1; pos--) {
                if (longestSubseqEndingInPos[pos] == longestIncreasingSubseqSize) {
                    solution.add(values[pos]);
                    longestIncreasingSubseqSize--;
                }
            }
            Collections.reverse(solution);

            return solution;
        }

        private static class BinaryIndexedTree {
            private int N;

            private int[] maxValues;

            public BinaryIndexedTree(int N) {
                this.N = N;
                this.maxValues = new int[N + 1];
                Arrays.fill(maxValues, 0);
            }

            int leastSignificantBit(int no) {
                return no & -no;
            }

            public void setPos(int pos, int value) {
                for ( ; pos <= N; pos += leastSignificantBit(pos)) {
                    maxValues[pos] = Math.max(maxValues[pos], value);
                }
            }

            public int getMaxFromOneToPos(int pos) {
                int bestResult = 0;
                for ( ; pos > 0 ; pos -= leastSignificantBit(pos)) {
                    bestResult = Math.max(bestResult, maxValues[pos]);
                }

                return bestResult;
            }
        }

        private static class NormalizedArray {
            int[] originalValues;

            int[] sortedUniqueValues;

            int uniqueElemsCount;
            
            public NormalizedArray(int[] originalValues) {
                this.originalValues = originalValues;
                sortedUniqueValues = Arrays.copyOfRange(originalValues, 0, originalValues.length);
                Arrays.sort(sortedUniqueValues);

                uniqueElemsCount = 1;
                for (int pos = 2; pos < sortedUniqueValues.length; pos++) {
                    if (sortedUniqueValues[pos] > sortedUniqueValues[pos - 1]) {
                        sortedUniqueValues[++uniqueElemsCount] = sortedUniqueValues[pos];
                    }
                }
            }

            public int getTotalUniqueElems() {
                return uniqueElemsCount;
            }

            public int getNormalizedValue(int pos) {
                return Arrays.binarySearch(sortedUniqueValues, 1, uniqueElemsCount + 1, originalValues[pos]);
            }
        }
    }

    static class InputReader implements AutoCloseable {

        private BufferedReader bufferedReader;

        private StringTokenizer stringTokenizer;

        public InputReader(InputStream inputStream) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            stringTokenizer = null;
        }

        private String nextToken() {
            if (stringTokenizer == null || !stringTokenizer.hasMoreTokens()) {
                try {
                    stringTokenizer = new StringTokenizer(bufferedReader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            return stringTokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(nextToken());
        }

        @Override
        public void close() throws Exception {
            bufferedReader.close();
        }
    }
}