백준

13398번 연속합 2 / BOJ

건이두 2020. 3. 23. 13:42
728x90

13398번 연속합 2 / BOJ
문제링크 : https://www.acmicpc.net/problem/13398
제출링크 : https://www.acmicpc.net/source/18618083
자바소스 : https://github.com/skysign/WSAPT/blob/master/BOJ/13398%EB%B2%88%20%EC%97%B0%EC%86%8D%ED%95%A9%202/src/Main.java

이 문제를 풀기 전에, 1912번 연속합 / BOJ 문제를 꼭 풀어보시고,
여기 참고하세요 → https://skysign.tistory.com/193

Dynamic Programming과 Prefix Sum을 사용해서 푸는 문제입니다.
이 문제에 대한 설명은 여기 참고하세요 → https://cooling.tistory.com/3

자세한 설명은 추후에 시간이 나면 추가하겠습니다. ^^a

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * 13398번 연속합 2 / BOJ
 * 문제링크 : https://www.acmicpc.net/problem/13398
 * 제출링크 : https://www.acmicpc.net/source/18618083
 * 문제해설 : https://skysign.tistory.com/194
 */
/**
 * 테스트 케이스
 * 1
 * -1
 * 답 -1
 * 여기서 답으로 0이 나오면 틀린 값입니다.
 * 한개를 삭제한다는 조건 보다, 한개이상 선택해야 한다는 조건이 우선입니다.
 *
 * 10
 * 1 -1 1 -1 1 -1 1 -1 1 -1
 * 답 2
 *
 * 3
 * -1 -1 -1
 * 답 -1
 *
 * 2
 * 1 -3
 * 답 1
 *
 * 2
 * -3 1
 * 답 1
 *
 * 3
 * -1 1 0
 * 답 1
 *
 * 3
 * -1 0 1
 * 답 1
 *
 * 3
 * 0 1 -1
 * 답 1
 *
 * 3
 * 1 0 -1
 * 답 1
 *
 * 3
 * 1 -1 1
 * 답 2
 *
 * 3
 * -1 1 1
 * 답 2
 *
 * 3
 * 1 1 -1
 * 답 2
 *
 * 3
 * -1 -1 1
 * 답 1
 *
 * 3
 * 1 -1 -1
 * 답 1
 *
 * 3
 * -1 1 -1
 * 답 1
 */
public class Main {
    int N;
    static int MY_MIN_VALUE = -100000;

    public void solve() throws IOException {
        N = sc.nextInt();
        int[] dt = new int[N];

        for (int i = 0; i < N; ++i) {
            dt[i] = sc.nextInt();
        }

        int[] dpL2R = new int[dt.length +1];
        long r = getSequenceNumberMax(dt, dpL2R);
        dpL2R[0] = Integer.MIN_VALUE;

        if(N>1) {
            int[] dpR2L = new int[dt.length +1];
            for(int i=N-1; i>=0; --i) {
                dpR2L[i] = Math.max(dt[i], dt[i] + dpR2L[i+1]);
            }
            dpR2L[N] = Integer.MIN_VALUE;

            // 하나 제거하는 수의 인덱스가 i 라고 할 때,
            for(int i=0; i<N; ++i) {
                // 0 부터 시작해서 i-1까지, 연속된 수의 최대 값
                // (연속된 수에 i-1은 포함되어있음)
                // dpL2R[i];
                r = Math.max(r, (long)dpL2R[i]);

                // i+1 부터 시작해서 N-1까지, 연속된 수의 최대 값
                // (연속된 수에 i+1은 포함되어있음)
                // dpR2L[i+1];
                r = Math.max(r, (long)dpR2L[i+1]);

                // 왼쪽 0~i-1 과 오른쪽 i+1 ~ N-1, 양쪽의 합
                r = Math.max(r, (long)dpL2R[i] + (long)dpR2L[i+1]);
            }
        }

        println(r);
    }

    public int getSequenceNumberMax(int[] dt, int[] dp) {
        int r = Integer.MIN_VALUE;

        for(int i=1; i<dt.length+1; ++i) {
            dp[i] = Math.max(dt[i-1], dt[i-1] + dp[i-1]);
            r = Math.max(r, dp[i]);
        }

        return r;
    }

//    * 아이디어
//    하나빼는 것을 실제로 빼지 말고, 0 으로 바꿔서
//    연속된 수의 최대값 구하기
//
//    답은 나오지만, 여전히 시간 초과로 오답 처리됨
//    O(N^2) 이고, N 의 범위가 1≤n≤100,000
//    worst case 는 10,000,000,000 약 100억번
//    1억~5억 정도가 1초안에 실행될 것으로 예상하는대,
//    100억번은 1초안에 실행되기에는 무리임
//
//    O(N)으로 문제를 해결해야 함
//
//    public void solve() throws IOException {
//        N = sc.nextInt();
//        int[] dt = new int[N];
//
//        for(int i=0; i<N; ++i) {
//            dt[i] = sc.nextInt();
//        }
//
//        int r = getSequenceNumberMax(dt);
//
//        for(int i=0; i<N; ++i) {
//            int tmp = dt[i];
//            dt[i] = 0;
//            r = Math.max(r, getSequenceNumberMax(dt));
//            dt[i] = tmp;
//        }
//
//        println(r);
//    }
//
//    // + O(N) N 개 입력 받기
//    // + O(N) N 개에서 하나도 빼지 않고, 연속된 수의 최대값
//    // O(N^2) N개 에서 하나씩 빼면서, 연속된 수의 최대값 구하기
//
//    public int getSequenceNumberMax(int[] dt) {
//        int dp[] = new int[dt.length +1];
//        int r = Integer.MIN_VALUE;
//
//        for(int i=1; i<dt.length+1; ++i) {
//            dp[i] = Math.max(dt[i-1], dt[i-1] + dp[i-1]);
//            r = Math.max(r, dp[i]);
//        }
//
//        return r;
//    }

//    * 아이디어
//    ArrayList를 사용해서, 한개를 제거한 배열을 만들고, 연속된 수의 최대갑 구하기
//
//    답은 나오지만, 제출하면 시간 초과로 오답 처리 됨, 시간이 오래 걸린 것으로 예상되는 부분
//    - ArrayList에서 하나 삭제하기
//    - ArrayList에서 하나 삭제한 다음에, 배열로 만들기
//    - ArrayList에서 하나 추가하기
//
//    public void solve() throws IOException {
//        N = sc.nextInt();
//        al = new ArrayList<>();
//
//        for(int i=0; i<N; ++i) {
//            al.add(sc.nextInt());
//        }
//
//        int max = Integer.MIN_VALUE;
//
//        for(int i=0; i<N; ++i) {
//            int tmpRemoved = al.get(i);
//            al.remove(i);
//            Integer[] dt = new Integer[al.size()];
//            dt = al.toArray(dt);
//            int myMax = getSequenceNumberMax(dt);
//            max = Math.max(max, myMax);
//            al.add(i, tmpRemoved);
//        }
//
//        println(max);
//    }
//
//    public int getSequenceNumberMax(Integer[] dt) {
//        int dp[] = new int[dt.length +1];
//        int r = Integer.MIN_VALUE;
//
//        for(int i=1; i<dt.length+1; ++i) {
//            dp[i] = Math.max(dt[i-1], dt[i-1] + dp[i-1]);
//            r = Math.max(r, dp[i]);
//        }
//
//        return r;
//    }

    public void _solve() throws IOException {
        solve();
        bw.flush();
    }

    public static void main(String[] args) throws IOException {
        Main main = new Main();
        main._solve();
    }

    public class MNode<TV> extends Node {
        ArrayList<MNode<TV>> mChidren ;

        MNode(TV v) {
            super(v);
            mChidren = new ArrayList<>();
        }
    }

    public class BNode<TV> extends Node {
        BNode<TV> mL;
        BNode<TV> mR;

        BNode(TV v) {
            super(v);
        }
    }

    public class Node<TV> {
        public TV mV;

        Node(TV v) {
            set(v);
        }

        public void set(TV v) {
            mV = v;
        }
    }

    public int[][] pSum2D(int[][] dt) {
        int[][] pSum2D = new int[dt.length][dt[0].length];
        return _prefixSum2D(dt, pSum2D, dt.length, dt[0].length);
    }

    public int[][] pSum2D(int[][] dt, int[][] pSum2D) {
        return _prefixSum2D(dt, pSum2D, dt.length, dt[0].length);
    }

    public int[][] _prefixSum2D(int[][] dt, int[][] pSum2D, int I, int J) {
        pSum2D[0][0] = dt[0][0];
        for(int j=1; j<J; ++j) {
            pSum2D[0][j] = dt[0][j] + pSum2D[0][j-1];
        }

        for(int i=1; i<I; ++i) {
            pSum2D[i][0] = dt[i][0] + pSum2D[i-1][0];
        }

        for(int i=1; i<I; ++i) {
            for(int j=1; j<J; ++j) {
                pSum2D[i][j] = dt[i][j] + pSum2D[i-1][j] + pSum2D[i][j-1] - pSum2D[i-1][j-1];
            }
        }

        return pSum2D;
    }

    public int area2DbyCnt(int[][] pSum2D, int i1, int j1, int i2, int j2) {
        return area2DbyIdx(pSum2D, i1-1, j1-1, i2-1, j2-1);
    }

    public int area2DbyIdx(int[][] pSum2D, int i1, int j1, int i2, int j2) {
        int r = pSum2D[i2][j2];

        if(i1>0)
            r -= pSum2D[i1-1][j2];
        if(j1>0)
            r -= pSum2D[i2][j1-1];

        if((i1>0) && (j1>0))
            r += pSum2D[i1-1][j1-1];

        return r;
    }

    public int[][] rotate90(int[][] a, int N) {
        int[][] tp = new int[N][N];

        for(int i=0; i<N; ++i) {
            for(int j=0; j<N; ++j) {
                tp[i][j] = a[N-1-j][i];
            }
        }

        return tp;
    }

    public int[][] rotate180(int[][] a, int N) {
        int[][] tp = new int[N][N];

        for(int i=0; i<N; ++i) {
            for(int j=0; j<N; ++j) {
                tp[N-i-1][N-j-1] = a[i][j];
            }
        }

        return tp;
    }

    public int[][] rotate270(int[][] a, int N) {
        int[][] tp = new int[N][N];

        for(int i=0; i<N; ++i) {
            for(int j=0; j<N; ++j) {
                tp[N-1-j][i] = a[i][j];
            }
        }

        return tp;
    }

    public void flip_h(int[][] a, int N) {
        for(int i=0; i<N; ++i) {
            for(int j=0; j<N/2; ++j) {
                int tp = a[i][N-j-1];
                a[i][N-j-1] = a[i][j];
                a[i][j] = tp;
            }
        }
    }

    public void flip_v(int[][] a, int N) {
        for(int i=0; i<N/2; ++i) {
            for(int j=0; j<N; ++j) {
                int tp = a[N-i-1][j];
                a[N-i-1][j] = a[i][j];
                a[i][j] = tp;
            }
        }
    }

    public int[][] clone2D(int[][] src) {
        int N = src.length;
        int[][] dst = new int[N][N];

        for (int i=0; i<N; i++) {
            System.arraycopy(src[i],0, dst[i],0, N);
        }

        return dst;
    }

    public class Pair<K, V> extends _Pair implements Comparable {
        public Pair(K key, V value) {
            super(key, value);
        }

        @Override
        public int compareTo(Object o) {
            Pair other = (Pair)o;
            int k1 = Integer.parseInt(this.getKey().toString());
            int k2 = Integer.parseInt(other.getKey().toString());

            if((k1 - k2) == 0) {
                int v1 = Integer.parseInt(this.getValue().toString());
                int v2 = Integer.parseInt(other.getValue().toString());
                return v1 - v2;
            }

            return k1 - k2;
        }
    }

    // http://cr.openjdk.java.net/~vadim/8140503/webrev.01/modules/base/src/main/java/javafx/util/Pair.java.html
    public class _Pair<K,V> {
        private K key;
        public K getKey() { return key; }
        private V value;
        public V getValue() { return value; }
        public _Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o instanceof _Pair) {
                _Pair pair = (_Pair) o;
                if (key != null ? !key.equals(pair.key) : pair.key != null) return false;
                if (value != null ? !value.equals(pair.value) : pair.value != null) return false;
                return true;
            }
            return false;
        }
    }

    // Normally used MIN/MAX number
    public final int _1087654321 = 1087654321;
    public final int __1087654321 = -1087654321;
    public final int _987654321 = 987654321;
    public final int __987654321 = -987654321;

    // Commonly used numbers as a divider of mod operation to prevent overflow
    public final int _10_007 = 10007;
    public final int _1_000_000_007 = 1000000007;
    final int MOD = _1_000_000_007;

    public void print(int v) throws IOException {
        print(v+"");
    }

    public void print(String s) throws IOException {
        bw.write(s);
    }

    public void println() throws IOException {
        print("\n");
    }

    public void println(int a) throws IOException {
        print(a+"\n");
    }

    public void println(long a) throws IOException {
        print(a+"\n");
    }

    public void println(double a) throws IOException {
        print(a+"\n");
    }

    public void println(String s) throws IOException {
        bw.write(s+"\n");
    }

    // -1
    public final int MINUS_1 = -1;

    // 4 ways
    public int[] d4i = new int[]{-1, 1, 0, 0};
    public int[] d4j = new int[]{0, 0, -1, 1};

    // 8 ways
    public int[] d8i = new int[]{-1, 1, 0, 0,  -1, -1, 1, 1};
    public int[] d8j = new int[]{0, 0, -1, 1,  -1, 1, 1, -1};

    // Initialize 2D arrays with value v
    public void fill2D(int[][] _2D, int v) {
        for(int[] _1D: _2D) {
            Arrays.fill(_1D, v);
        }
    }

    public void fill2D(long[][] _2D, long v) {
        for(long[] _1D: _2D) {
            Arrays.fill(_1D, v);
        }
    }

    public void fill2D(double[][] _2D, double v) {
        for(double[] _1D: _2D) {
            Arrays.fill(_1D, v);
        }
    }

    public void print2D(int[][] dp) throws IOException {
        print("    ");

        for(int j=0; j<dp[0].length; ++j){
            print(SS(j)+j + " ");
        }
        println();

        for(int i=0; i<dp.length; ++i){
            print(SS(i)+i+"|");
            for(int j=0; j<dp[0].length; ++j){
                print(SS(dp[i][j])+dp[i][j] + " ");
            }
            println();
        }
    }

    public void print2D(long[][] dp) throws IOException {
        print("    ");

        for(int j=0; j<dp[0].length; ++j){
            print(SS(j)+j + " ");
        }
        println();

        for(int i=0; i<dp.length; ++i){
            print(SS(i)+i+"|");
            for(int j=0; j<dp[0].length; ++j){
                print(SS(dp[i][j])+dp[i][j] + " ");
            }
            println();
        }
    }

    public final int LENGHT_OF_NUMBER = 3;
    /**
     * Generate space string for alignment when we print 2D arrays.
     * its length is LENGHT_OF_NUMBER - the length of number
     * Basically, we assume that number a is less than 1000.
     * So, LENGHT_OF_NUMBER is 3 by default.
     * @param a
     * @return
     */
    public String SS(int a) {
        String s = a+"";
        int l = LENGHT_OF_NUMBER - s.length();
        StringBuilder sb = new StringBuilder();

        for(int i=0; i<l; ++i) {
            sb.append(" ");
        }

        return sb.toString();
    }

    public String SS(long a) {
        String s = a+"";
        int l = LENGHT_OF_NUMBER - s.length();
        StringBuilder sb = new StringBuilder();

        for(int i=0; i<l; ++i) {
            sb.append(" ");
        }

        return sb.toString();
    }

    // Initialize 3D arrays with value v
    public void fill3D(int[][][] _3D, int v) {
        for(int[][] _2D: _3D) {
            for(int[] _1D: _2D) {
                Arrays.fill(_1D, v);
            }
        }
    }

    // GCD
    int GCD(int a, int b) {
        if(0 == b) {
            return a;
        }

        return GCD(b, a%b);
    }

    long GCD(long a, long b) {
        if(0 == b) {
            return a;
        }

        return GCD(b, a%b);
    }

    boolean IsEven(int a) {
        return (a>>1) == ((a>>1)<<1);
    }

    boolean IsOdd(int a) {
        return (a>>1) != ((a>>1)<<1);
    }

    boolean IsEven(long a) {
        return (a>>1) == ((a>>1)<<1);
    }

    boolean IsOdd(long a) {
        return (a>>1) != ((a>>1)<<1);
    }

    public Reader sc = new Reader();
//    Sometimes, Reader class cause unknown problem, when I submit my java code to judge server.
//    For more detail, please see https://algospot.com/forum/read/4731/
//    public Scanner sc = new Scanner(System.in);

    public BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

    // https://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/
    public class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String nextLine() throws IOException
        {
            byte[] buf = new byte[64]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }

//    public void test_matrix_methods() throws IOException {
//        // Test Case 1
//        int m1[][] = { {1, 2, 3, 4},
//                {5, 6, 7, 8},
//                {9, 10, 11, 12},
//                {13, 14, 15, 16} };
//
//        // Tese Case 2
//        int m2[][] = { {1, 2, 3},
//                {4, 5, 6},
//                {7, 8, 9} };
//
//        println("Matrix Original");
//        print2D(m1);
//
//        println("Matrix Rotate 90");
//        print2D(rotate90(m1, m1.length));
//
//        println("Matrix Rotate 180");
//        print2D(rotate180(m1, m1.length));
//
//        println("Matrix Rotate 270");
//        print2D(rotate270(m1, m1.length));
//
//        println("Matrix Flip Horizontal");
//        int[][] m1h = clone2D(m1);
//        flip_h(m1h, m1h.length);
//        print2D(m1h);
//
//        println("Matrix Flip Vertical");
//        int[][] m1v = clone2D(m1);
//        flip_v(m1v, m1v.length);
//        print2D(m1v);
//
//        println();
//
//        println("Matrix Original");
//        print2D(m2);
//
//        println("Matrix Rotate 90");
//        print2D(rotate90(m2, m2.length));
//
//        println("Matrix Rotate 180");
//        print2D(rotate180(m2, m2.length));
//
//        println("Matrix Rotate 270");
//        print2D(rotate270(m2, m2.length));
//
//        println("Matrix Flip Horizontal");
//        int[][] m2h = clone2D(m2);
//        flip_h(m2h, m2h.length);
//        print2D(m2h);
//
//        println("Matrix Flip Vertical");
//        int[][] m2v = clone2D(m2);
//        flip_v(m2v, m2v.length);
//        print2D(m2v);
//    }
//
//    public void test_pSum2D_methods() throws IOException {
//        // Test Case 1
//        int m1[][] = { {1, 1, 1, 1},
//                {1, 1, 1, 1},
//                {1, 1, 1, 1},
//                {1, 1, 1, 1} };
//
//        println("Matrix Original");
//        print2D(m1);
//
//        int[][] m1pSum2D = new int[m1.length][m1[0].length];
//        println("pSum2D");
//        pSum2D(m1, m1pSum2D);
//        print2D(m1pSum2D);
//
//        println(area2DbyIdx(m1pSum2D, 1, 1, 3, 3));
//        println(area2DbyIdx(m1pSum2D, 0, 0, 3, 3));
//        println(area2DbyIdx(m1pSum2D, 0, 1, 3, 3));
//        println(area2DbyIdx(m1pSum2D, 1, 0, 3, 3));
//    }
}
728x90