[SWEA] 3813. 그래도 수명이 절반이 되어서는...

Problem

제출일 : 2019-12-11

문제 풀이 시간 : 1H 45M

난이도 : ★★★★


link : https://swexpertacademy.com/main/learn/course/subjectDetail.do?subjectId=AWWxo6c6AVkDFAW4#

삼성전자에서 생산하는 플래시 드라이브를 포맷하는 프로그램을 작성하려고 한다.

드라이브를 포맷할 때 특정한 초기 데이터를 항상 드라이브에 저장해 두어야 한다. 이 데이터는 매우 자주 엑세스되는 종류라서 이 데이터가 저장된 블록은 수명이 짧아질 수 있다.

플래시 드라이브는 N개의 블록으로 구성된 것으로 생각하고 각 블록은 1부터 N까지 번호가 붙은 것으로 생각하자.

각 블록마다 지금까지 얼마나 많은 엑세스가 있었는지 알고 있어서 i번째 블록이 얼마나 닳았는지(Wear Level)를 표현하는 값 W를 모든 블록에 대해 가지고 있다고 한다.

Wi의 값은 1 이상 200,000 이하의 자연수 값이고, 값이 클수록 닳은 정도가 많아서 남은 수명이 짧다는 의미이다.

초기 데이터를 아무 곳에나 저장한다면 플래시 드라이브의 수명이 아주 작아질 수 있을 것이다.

“그래도 수명이 절반이 되어서는” 안된다는 정책에 따라서 초기 데이터를 플래시 드라이브의 적절한 위치에 배치하여 드라이브 수명을 최대한 길게 하고 싶다.

초기 데이터는 K개의 덩어리로 구성되어 있고, 이들 중 i번째 덩어리는 Si개의 연속된 블록에 저장되어야 한다.

또, 덩어리들은 입력에 주어진 순서대로 작은 번호의 블록부터 저장되어야 한다.

또, 하나의 덩어리가 저장된 블록에는 다른 덩어리를 저장할 수 없다.

위의 예는 플래시 드라이브 블록들의 Wear Level을 표시한 것이다.

초기 데이터가 3개의 덩어리로 구성되어 있고 각 덩어리의 블록 수가 2, 1, 3이라고 하면 다음과 같이 저장했을 때 최대 Wear Level이 3이 되어 최적이 된다.

입력으로 플래시 메모리의 블록 수 N, 각 블록의 Wear Level 값, 초기 데이터의 덩어리 수와 각덩어리가 차지하는 블록 수를 받아서 위의 조건을 만족하도록 저장할 때

가능한 최대 Wear Level의 최소값을 구하는 프로그램을 작성하라.

Constraints

  1. 플래시 드라이브의 블록 수 N은 최대 200,000이다. (1≤N≤200,000)

  2. 각 블록의 Wear Level 값은 1 이상 200,000이하의 자연수이다. (1≤Wi≤200,000)

  3. 초기 데이터의 덩어리 수 K는 1 이상 N 이하이다. (1≤K≤N)

  4. 초기 데이터의 덩어리 당 블록 수의 합은 1 이상 N 이하이다. (1≤S1+S2+…+SK≤N)

input

첫 줄에 테스트케이스의 개수 T가 주어진다. (1 ≤ T ≤ 50)

그 다음 줄부터는 각 테스트 케이스가 주어지며 각 테스트 케이스의 첫째 줄에는 N과 K의 값이 순서대로 주어진다.

다음 줄에는 W1, W2, …, WN이 순서대로 주어진다.

그 다음 줄에는 S1, S2, …, SK가 순서대로 주어진다.

Output

각 테스트케이스마다 한 줄에 걸쳐, 테스트케이스 수 “#(TC) “를 출력하고, 초기 데이터가 저장된 블록들의 최대 Wear Level의 가능한 최소값을 출력한다.

Example

input

3
9 3
5 2 3 6 1 4 1 3 2
2 1 3
9 2
1 2 3 4 5 6 7 8 9
2 3
9 2
1 2 3 4 5 4 3 2 1
2 3

output

#1 3
#2 5
#3 3

Solution & Inpression

입력이 가능한 최대 N은 200,000이다. 따라서 모든 경우의 수를 탐색하여 답을 구하는 방법으론 문제해결이 불가능한 문제이다.

일반 문제를 결정문제로 바꾸어 생각하여 문제를 풀어야 한다.

거꾸로 생각하는 것으로

답을 X라고 가정했을때 X가 답인 경우엔 X보다 큰 값은 모두 답이고, X가 답이 아닌 경우는 X보다 작은 값은 모두 답이 될 수 없다.

이런 아이디어를 갖고 문제를 접근한다면 보다 쉽게 문제를 해결할 수 있다. 이분탐색을 이용하여 범위를 계속 좁히며 $O(logN)$번의 탐색으로 최종해를 찾을 수 있다.

답이 가능한 경우와 답이 불가능한 경우는 어떻게 확인을 해야할까???

문제에서 입력으로 K개의 덩어리의 블록 수가 들어오는데 이를 배열S에 저장하고

입력받은 배열W를 순회하며 적합성을 파악한다.

Code

언어 : JAVA

import java.io.FileInputStream;
import java.util.Scanner;

public class Solution {
    final static int Max = 200009;
    static int[] W = new int[Max], S = new int[Max];
    static int N, K;

    public static void main(String[] args) throws Exception {
        System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();

        for (int tc = 1; tc <= T; tc++) {
            N = sc.nextInt();
            K = sc.nextInt();

            for (int i = 1; i <= N; i++)
                W[i] = sc.nextInt();
            for (int i = 1; i <= K; i++)
                S[i] = sc.nextInt();

            int s = 1, e = Max, m;
            while (s < e) {
                m = (s + e) / 2;
                if (isAvailable(m))
                    e = m;
                else
                    s = m + 1;
            }
            System.out.println("#" + tc + " " + s);
        } // end of TC
        sc.close();
    }// end of Main

    private static boolean isAvailable(int p) {
        int i, now = 1, cont = 0;
        for (i = 1; i <= N; ++i) {
            if (W[i] <= p)
                cont++;
            else
                cont = 0;
            if (cont == S[now]) {
                cont = 0;
                if (++now > K)
                    break;
            }
        }
        return now > K;
    }

}

운영체제의 개요

운영체제의 개념

사용자

  • 컴퓨터를 사용하는 사람이나 장치, 다른 컴퓨터 등을 의미

소프트웨어

  • 컴퓨터의 기능 수행에 필요한 모든 프로그램

하드웨어

  • 기본 연산 자원을 제공하는 프로세서(CPU, 중앙처리장치), 메모리, 주변장치 등

운영체제의 정의

  • 사용자와 하드웨어 사이의 중간 매개체로 응용 프로그램의 실행을 제어하고, 자원을 할당 및 관리하며, 입출력 제어 및 데이터 관리와 같은 서비스를 제공하는 소프트웨어
  • 응용 프로그램이나 사용자에게 컴퓨터 자원을 사용할 수 있는 인터페이스를 제공하고 그 결과를 돌려주는 시스템 소프트웨어
  • 응용 프로그램이나 사용자에게 모든 컴퓨터 자원을 숨기고 정해진 방법으로만 컴퓨터 자원을 사용할 수 있도록 제한

운영체제의 역할

  • 하드웨어 및 사용자, 응용 프로그램, 시스템 프로그램 사이에서 인터페이스를 제공

  • 프로세서, 메모리, 입출력장치, 통신장치 등 컴퓨터 자원을 효과적으로 활용하려고 조정·관리

  • 메일 전송, 파일 시스템 검사, 서버 작업 등 높은 수준의 서비스를 처리하는 응용 프로그램을 제어

  • 다양한 사용자에게서 컴퓨터 시스템을 보호하려고 입출력을 제어하며 데이터를 관리

자원 관리

  • 컴퓨터 시스템의 자원을 응용 프로그램에 나누어주어 사용자가 원활하게 작업할 수 있도록 함

  • 자원을 요청한 프로그램이 여러 개라면 적당한 순서로 자원을 배분하고 적절한 시점에 자원을 회수하여 다른 응용 프로그램에 나누어줌

자원 보호

  • 비정상적인 작업으로부터 컴퓨터 자원을 보호

하드웨어 인터페이스 제공

  • 사용자가 복잡한 과정 없이 다양한 장치를 사용할 수 있도록 해주는 하드웨어 인터페이스 제공

  • CPU, 메모리, 키보드, 마우스와 같은 다양한 하드웨어를 일관된 방법으로 사용할 수 있도록 지원

사용자 인터페이스 제공

  • 사용자가 운영체제를 편리하게 사용하도록 지원(예: 윈도우의 그래픽 사용자 인터페이스(GUI))

운영체제의 필요성

운영체제와 관련된 질문

  1. 컴퓨터는 운영체제가 없어도 작동하는가?
    • 컴퓨터는 운영체제가 없어도 작동하지만 기능에 제약이 따른다.
  2. 운영체제가 있는 기계와 없는 기계는 어떤 차이가 있는가?
    • 운영체제가 있는 기계는 다양한 응용프로그램을 설치하여 사용할 수 있고 성능 향상을 위한 새로운 기능을 쉽게 추가할 수 있다.
  3. 운영체제는 성능을 향상하는 데에만 필요한가?
    • 운영체제는 컴퓨터의 성능을 향상할 뿐 아니라 자원을 관리하고 사용자에게 편리한 인터페이스 환경을 제공한다.
  4. 운영체제는 자원을 어떻게 관리하는가?
    • 운영체제는 사용자가 직접 자원에 접근하는 것을 막음으로써 컴퓨터 자원을 보호한다.
  5. 사용자는 숨어있는 자원을 어떻게 이용할 수 있는가?
    • 운영체제가 제공하는 사용자 인터페이스와 하드웨어 인터페이스를 이용하여 자원에 접근한다.

운영체제의 목표

운영체제의 목표

효율성

  • 자원을 효율적으로 관리하는 것
  • 같은 자원을 사용하여 더 많은 작업량을 처리하거나, 같은 작업량을 처리하는 데 보다 적은 자원을 사용하는 것

안정성

  • 작업을 안정적으로 처리하는 것

  • 사용자와 응용 프로그램의 안전 문제와 하드웨어적인 보안 문제 처리

  • 시스템에 문제가 발생했을 때 이전으로 복구하는 결함 포용 기능 수행

확장성

  • 다양한 시스템 자원을 컴퓨터에 추가하거나 제거하기 편리한 것

편리성

  • 사용자가 편리하게 작업할 수 있는 환경을 제공하는 것
  • 프로그램 개발 환경뿐만 아니라 응용 프로그램에 대한 사용자 인터페이스, 즉 사용자와 컴퓨터 시스템이 정보 및 명령을 상호 교환할 수 있는 인터페이스 제공

운영체제의 기능

자원관리

자원: 컴퓨터 시스템의 메모리, 프로세스, 장치, 파일등의 구성 요소

메모리 관리

메인메모리 관리
  • 메모리의 어느 부분을 사용하고, 누가 사용하는지 점검
  • 메모리에 저장할 프로세스 결정
  • 메모리를 할당하고 회수하는 방법 결정
보조기억장치 관리
  • 빈 여유 공간 관리
  • 새로운 파일 작성 시 저장 장소 할당
  • 메모리 접근 요청 스케줄링
  • 파일을 생성하고 삭제

프로세스 관리

  • 프로세스와 스레드 스케줄링
  • 사용자 프로세스와 시스템 프로세스 생성, 제거
  • 프로세스 중지, 재수행
  • 프로세스 동기화 방법 제공
  • 프로세스 통신 방법 제공
  • 교착 상태를 방지하는 방법 제공

주변장치(입출력 장치) 관리

  • 임시 저장(buffer-caching) 시스템 기능 제공

  • 일반 장치용 드라이버 인터페이스 제공

  • 특정 장치 드라이버 제공

파일(데이터) 관리

  • 파일 생성, 삭제

  • 디렉터리 생성, 삭제

  • 보조기억장치의 파일 맵핑

  • 저장장치에 파일 저장

시스템 관리

시스템 보호(사용자 권한 부여)

  • 보호 : 컴퓨터 자원에서 프로그램, 프로세스, 사용자의 접근 제어 방법
  • 운영체제는 파일 사용 권한 부여, 데이터 암호화 등 서비스를 제공, 데이터와 시스템 보안
  • 컴퓨터 시스템에서는 여러 프로세스 동시 실행 가능하므로 상호 보호해야 함
  • 네트워크로 파일 공유 사이트에 접속 시 다른 사용자의 프로그램에서 보호

네트워킹(통신)

  • 프로세서는 다양한 방법으로 구성된 네트워크 이용, 완전 접속과 부분 접속 방법으로 연결
  • 연결된 프로세서가 통신을 할 때는 경로 설정, 접속 정책, 충돌, 보안 등 고려(운영체제가 관리)

명령 해석기

  • 명령 해석기(command interpreter)는 운영체제에서 중요한 시스템 프로그램
  • 대화형으로 입력한 명령어를 이해하고 실행하는 사용자와 운영체제의 인터페이스
  • 사용자가 입력한 명령은 제어문으로 운영체제에 전달하는데, 이 전달을 명령 해석기가 담당
  • 인터페이스 역할을 할 뿐 운영체제는 아님
  • 커널과 분리하는 것이 좋음(명령 해석기의 인터페이스 변경 가능)
    • 분리하지 않으면 사용자가 커널의 코드를 변경할 수 없어 인터페이스를 변경 불가

운영체제 역사

연도 운영체제 특징
1940년대 운영체제 없음(작업별 순차 처리) - 기계어를 직접 사용
- 단순 순차 처리
1950년대 일괄 처리 시스템 - 작업별로 일괄 처리
- 버퍼링, 스풀링 방법 등장
1960년대 다중 프로그래밍 시스템
시분할 시스템
다중 처리 시스템
실시간 처리 시스템
- 가상 기억장치 등장
- 다중 프로그래밍, 다충 처리, 시분할 처리 등의 개념 등장
- 운영체제를 고급 언어로 작성
- 데이터 통신 지원용 운영체제 사용
1970년대 초반 다중 모드 시스템
범용 시스템
- 일괄 처리, 시분할 처리, 실시간 처리, 다중 프로그래밍 등을 제공하는 다중 모드 시세템 등장
- 장치의 독립성 제공
- TCP/IP 통신 표준 활성화
- 운영체제가 네트워크와 보안을 아우르는 수준으로 발전
1970년대 중반 분산 처리 시스템 - 각종 응용 프로그램 개발 및 데이터베이스 활용 확대
- 네트워크 기술 발전
- 하드웨어에 운영체제 개념이 포함된 펌웨어 개념 등장
1990년대 병렬 계산과 분산 계산 - 월드와이드웹의 등장으로 분산 컴퓨팅 증가
- GUI강화
- 개인용과 서버용 운영체제의 보편화
2000년대 이후 모바일 및 임베디드
가상화 및 클라우드 컴퓨팅
- 네트워크 기반의 분산 및 병렬 운영체제의 보편화
- 모바일 장치와 가전제품을 위한 모바일 및 임베디드 운영체제의 보편화
- 다양한 기능, 확장성과 호환성 극대화
- 다양한 통신망의 확대와 개발형 시스템 발달
- 여러 운영체제가 한 시스템의 자원을 공유할 수 있게 해주는 서버 가상화 기술의 확산
- 컴퓨팅 자원, 스토리지, 소프트웨어 등을 사용자에게 서비스 형태로 제공하는 클라우드 컴퓨팅의 등장

운영체제의 유형

일괄 처리 시스템

일괄 처리 시스템은 초기의 컴퓨터 시스템에서 사용된 형태로, 일정량 또는 일정 기간 동안 데이터를 모아서 한꺼번에 처리하는 방식

  • 유휴 상태의 시간을 없애기 위해 여러개의 작업을 단일 작업으로 만듬

  • 작업의 준비 및 실행 순서를 자동화함으로써 시스템의 성능을 높임

  • 작업을 실행하면 끝날때까지 아무것도 할 수 없음

다중 프로그래밍 시스템

하나의 CPU와 주기억장치를 이용하여 여러개의 프로그램을 동시에 처리하는 방식

  • 한 번에 하나의 작업만 가능한 일괄 처리 시스템에 비해 효율성이 뛰어남

  • 시간을 분할하는 방법 때문에 여러 작업이 동시에 실행되는 것처럼 보임

    • 프로그램들 사이에 스케줄링을 통하여 CPU사용을 늘림
    • CPU 사용 시간을 아주 잘게 쪼개어 여러 작업에 나누어줌
  • 여러 작업을 준비 상태로 두려면 이를 메모리에 보관, 일정 형태의 메모리를 관리해야 함
    여러 작업이 수행할 준비를 갖추고 있으면, 이 중 하나를 선택하는 결정 방법 필요

시분할 시스템

여러 명의 사용자가 사용하는 시스템에서 컴퓨터가 사용자들의 프로그램을 번갈아가며 처리해줌으로써 각 사용자에게 독립된 컴퓨터를 사용하는 느낌을 주는 것으로, 라운드 로빈(Round Robin)방식이라고도 함

  • 다중 프로그래밍을 논리적으로 확장한 개념, 프로세서가 다중 작업을 교대로 수행
  • 다수의 사용자가 동시에 컴퓨터의 자원을 공유할 수 있는 기술
  • 여러 사용자에게 짧은 간격으로 프로세서 번갈아 할당, 마치 자기 혼자 프로세서를 독점하고 있는 양 착각하게 하여 여러 사용자가 단일 컴퓨터 시스템을 동시 사용 가능
  • CPU 사용 시간을 잘게 쪼개어 작업들에 나누어줌으로써 모든 작업이 동시에 처리되는 것처럼 보임

다중 처리 시스템

여러개의 CPU와 하나의 주기억장치를 이용하여 여러 개의 프로그램을 동시에 처리하는 방식

  • 여러 프로세서와 시스템 버스, 클록, 메모리와 주변장치 등 공유

  • 빠르고, 프로세서 하나가 고장 나도 다른 프로세서 사용하여 작업 계속, 신뢰성 높음

  • 프로세서 간의 연결, 상호작용, 역할 분담 등을 고려해야 함

  • 다중 처리 시스템을 구성하는 방법에는 비대칭(주종)적 구성과 대칭적 구성이 있음

실시간 처리 시스템

데이터 발생 즉시, 또는 데이터 처리 요구가 있는 즉시 처리하여 결과를 산출하는 방식

  • 처리시간이 단축되고, 처리 비용이 절감

실시간 처리 시스템의 두 가지 유형

경성 실시간 처리 시스템(hard real time processing system)
  • 작업의 실행 시작이나 완료에 대한 시간 제약 조건을 지키지 못할 때 시스템에 치명적인 영향을 주는 시스템

  • 무기 제어, 발전소 제어, 철도 자동 제어, 미사일 자동 조준 등이 이에 해당

  • 보장되는 컴퓨팅, 시간의 정확성과 컴퓨팅 예측성을 갖게 해야 함

연성 실시간 처리 시스템(soft real time processing system)
  • 작업 실행에서 시간 제약 조건은 있으나, 이를 지키지 못해도 전체 시스템에 치명적인 영향을 미치지 않는 시스템

  • 동영상은 초당 일정 프레임frame 이상의 영상을 재생해야 한다는 제약이 있으나, 일부 프레임을 건너뛰어도 동영상을 재생 시스템에는 큰 영향을 미치지 않음

분산 처리 시스템

여러개의 컴퓨터(프로세서)를 통신 회선으로 연결하여 하나의 작업을 처리하는 방식

  • 시스템마다 독립적인 운영체제와 메모리로 운영, 필요 시 통신하는 시스템

  • 사용자에게는 중앙집중식 시스템처럼 보이는데, 다수의 독립된 프로세서에서 실행

  • 데이터를 여러 위치에서 처리·저장, 여러 사용자가 공유

  • 하나의 프로그램을 여러 프로세서에서 동시에 실행

운영체제의 구조

커널과 인터페이스

커널

  • 프로세스 관리, 메모리 관리, 저장장치 관리와 같은 운영체제의 핵심적인 기능을 모아놓은 것

인터페이스

  • 커널에 사용자의 명령을 전달하고 실행 결과를 사용자에게 알려주는 역할

  • 그래픽을 사용한 인터페이스를 GUI(graphical User Interface)라 부름

시스템 호출과 디바이스 드라이버

시스템 호출

  • 커널이 자신을 보호하기 위해 만든 인터페이스

  • 커널은 사용자나 응용 프로그램으로부터 컴퓨터 자원을 보호하기 위해 자원에 직접 접근하는 것을 차단

    • 응용 프로그램이 하드웨어 자원에 접근하거나 운영체제가 제공하는 서비스를 이용하려 할 때는 시스템 호출을 사용해야 함

    • 운영체제는 커널이 제공하는 서비스를 시스템 호출로 제한하고 다른 방법으로 커널에 들어오지 못하게 막음으로써 컴퓨터 자원을 보호

    • 시스템 호출은 커널이 제공하는 서비스를 이용하기 위한 인터페이스이며, 사용자가 자발적으로 커널 영역에 진입할 수 있는 유일한 수단임

직접 접근
  • 두 응용 프로그램이 자기 마음에 드는 위치에 데이터를 저장하려고 함

  • 다른 사람의 데이터를 지울 수도 있고 내 데이터가 다른 사람에 의해 지워질 수도 있음

시스템 호출을 통한 접근
  • 응용 프로그램이 직접 하드디스크에 데이터를 저장하지 않고 커널이 제공하는 write( ) 함수를 사용하여 데이터를 저장해달라고 요청

  • 커널이 데이터를 가져오거나 저장하는 것을 전적으로 책임지기 때문에 컴퓨터 자원 관리가 수월

드라이버

  • 커널과 하드웨어의 인터페이스 담당하며 디바이스 드라이버라고도 불림

  • 마우스와 같이 간단한 제품은 드라이버를 커널이 가지고 있으나, 그래픽카드와 같이 복잡한 하드웨어의 경우 제작자가 드라이버를 제공 함

커널의 구성

단일형 구조 커널

  • 초창기의 운영체제 구조

  • 커널의 핵심 기능을 구현하는 모듈들이 구분 없이 하나로 구성

<장점>
  • 모듈 간의 통신 비용이 줄어들어 효율적인 운영이 가능
<단점>
  • 모든 모듈이 하나로 묶여 있기 때문에 버그나 오류를 처리하기가 어려움
  • 운영체제의 여러 기능이 서로 연결되어 있어 상호 의존성이 높기 때문에 기능상의 작은 결함이 시스템 전체로 확산될 수 있음
  • 다양한 환경의 시스템에 적용하기 어려움
  • 현대의 운영체제는 매우 크고 복잡하기 때문에 완전 단일형 구조의 운영체제를 구현하기가 어려움

계층형 구조 커널

  • 비슷한 기능을 가진 모듈을 묶어서 하나의 계층으로 만들고 계층 간의 통신을 통해 운영체제를 구현하는 방식

마이크로 구조 커널

  • 프로세스 관리, 메모리 관리, 프로세스 간 통신 관리 등 가장 기본적인 기능만 제공

  • 커널의 각 모듈은 세분화되어 존재하고 모듈 간의 정보 교환은 프로세스 간 통신을 이용하여 이루어짐

Reference

IT CookBook, 운영체제(개정3판)』, 구현회 집필, 한빛아카데미

IT CookBook, 쉽게 배우는 운영체제』, 조성호 집필, 한빛아카데미

운영체제 : 내부구조 및 설계원리 (6판)』, WILLIAM STALLINGS 저, PEARSON HALL

'OS' 카테고리의 다른 글

05. 상호배제와 동기화 [2/2]  (0) 2019.12.15
05. 상호배제와 동기화 [1/2]  (0) 2019.12.15
04. 병행 프로세스  (0) 2019.12.15
03. 스레드(Thread)  (1) 2019.12.15
02. 프로세스  (0) 2019.12.14

[SWEA] 3816. 아나그램

제출일 : 2019-12-11

문제 풀이 시간 : 1H 45M

난이도 : ★★★

Problem

link : https://swexpertacademy.com/main/learn/course/subjectDetail.do?subjectId=AWWxo6c6AVkDFAW4#

아나그램이란 문자열의 문자들을 모두 사용하여 재배열한 것을 의미한다.

“abc”의 아나그램은 “abc”, “acb”, “bac”, “bca”, “cab”, “cba” 총 6개이다.

문자열 S1, S2이 차례대로 주어진다. S2의 부분문자열 중 S1의 아나그램인 것의 개수를 구하는 프로그램을 작성하라.

input

첫 줄에 테스트케이스의 개수 T가 주어진다. (T ≤ 20)

각 테스트케이스의 첫 줄에 S1, S2가 사이에 공백을 갖고 띄어져 있다.

S1과 S2는 영문 소문자로만 이루어져 있다. (1 ≤ |S1| ≤ |S2| ≤ 100,000)(|S1|, |S2|는 문자열 S1, S2의 길이)

Output

각 테스트케이스마다 한 줄에 걸쳐, 테스트케이스 수 “#(TC) “를 출력하고, 해당 테스트케이스의 아나그램인 것의 개수를 출력한다.

Example

input

4
aba ababababa
abra abracadabra
anan bananaparanabrazil
ab abba

output

#1 4
#2 2
#3 2
#4 2

Solution & Inpression

아나그램이란 문자열의 문자들을 모두 사용하여 재배열한 것이므로 아나그램이 가능한 경우는 사용되는 알파벳의 조합과 그 숫자가 정확하게 일치될때 아나그램이라고 말한다.

따라서 S2의 부분 문자열이 S1의 아나그램이 되려면 S1이 가진 알파벳의 조합과 사용된 수를 구해 counts 배열에 저장하고 각각 탐색하면서 문제를 해결한 풀이가 code1의 풀이이다.

code1의 풀이는 어렵지 않게 구현이 가능했다.

code2는 S2의 부분 문자열을 탐색할때 순차적으로 탐색을 하기에 맨앞의 알파벳과 맨 뒤의 알파벳만이 변경되며 나머지 알파벳은 그대로 사용되기에 양 끝의 알파벳만 확인하며 아나그램을 찾았다.

Code 1

언어 : JAVA

import java.io.FileInputStream;
import java.util.Scanner;

public class Solution {
    public static void main(String[] args) throws Exception {
        //System.setIn(new FileInputStream("res/input.txt"));

        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();

        for (int tc = 1; tc <= T; tc++) {
            char[] s1 = sc.next().toCharArray();
            char[] s2 = sc.next().toCharArray();
            int[] counts = new int[26];

            for (int i = 0; i < s1.length; i++) {
                counts[s1[i] - 'a']++;
            }

            int ans = 0;

            for (int i = 0; i < s2.length - s1.length + 1; i++) {
                int[] tmp = new int[26];
                for (int j = i; j < s1.length + i; j++) {
                    tmp[s2[j] - 'a']++;
                }
                boolean flag = true;
                for (int k = 0; k < 26; k++) {
                    if (tmp[k] != counts[k]) {
                        flag = false;
                        break;
                    }
                }
                if (flag)
                    ans++;
            }

            System.out.println("#" + tc + " " + ans);

        } // end of TC

    }// end of main
}

Code 2

언어 : JAVA

import java.io.FileInputStream;
import java.util.Scanner;

public class Solution {
    public static void main(String[] args) throws Exception {
        //System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();

        for (int tc = 1; tc <= T; tc++) {
            String str1 = sc.next();
            String str2 = sc.next();

            int ans = 0;
            int[] counts = new int[26];

            for (int i = 0; i < str1.length(); i++) {
                counts[str1.charAt(i) - 'a']++;
            }

            int zero = 0;
            for (int i = 0; i < 26; i++) {
                if (counts[i] == 0) {
                    zero++;
                }
            }

            int len = str1.length();
            for (int i = 0; i < str2.length(); i++) {
                char a = str2.charAt(i);

                if (counts[a - 'a'] == 0) {
                    zero--;
                }
                counts[a - 'a']--;
                if (counts[a - 'a'] == 0) {
                    zero++;
                }


                if (i >= len) {
                    char b = str2.charAt(i - len);
                    if (counts[b - 'a'] == 0) {
                        zero--;
                    }
                    counts[b - 'a']++;
                    if (counts[b - 'a'] == 0) {
                        zero++;
                    }
                }


                if (zero == 26) {
                    ans++;
                }
            }
            System.out.println("#" + tc + " " + ans);
        }
    }
}

[SWEA] 3819. 최대 부분 배열

제출일 : 2019-12-09

문제 풀이 시간 : 1H 45M

난이도 : ★★★☆

Problem

link : https://swexpertacademy.com/main/learn/course/subjectDetail.do?subjectId=AWWxo6c6AVkDFAW4#

길이 $N$ 짜리 배열$A[1…N]$이 주어질 때,

부분 배열의 합 $\sum_{k=i}^j A[k]$의 최댓값을 구하는 프로그램을 작성하라. $(1 ≤ i ≤ j ≤ N)$

input

첫 줄에 테스트케이스의 개수 $T$가 주어진다. $(T ≤ 20)$

각 테스트케이스마다 첫 줄에 $N(N ≤ 200,000)$이 주어지고, 다음 $N$ 줄에 걸쳐 각 줄마다 차례대로 $A[i]$가 주어진다.$(|A[i]| ≤ 1,000)$

Output

각 줄마다 "#T" (T는 테스트 케이스 번호)를 출력한 뒤, 러시아 국기 같은 깃발을 만들기 위해서 새로 칠해야 하는 칸의 개수의 최솟값을 구하여 T 줄에 걸쳐서 출력한다.

Example

input

2
1
3
5
1
3
-5
3
6

output

#1 3
#2 9

Solution & Inpression

길이 N의 최대값이 200,000이기때문에 모든 경우의 수를 구해 최적해를 구하는 방법으론 풀수 없는 문제로
$$
\sum_{k=i}^j A[k]= \sum_{k=1}^j A[k]-\sum_{k=1}^i A[k]
$$
i부터 j까지의 부분 배열의 합은 1부터 j까지의 부분배열의 합에서 1부터 i까지의 부분배열의 합을 뺀것과 같다.

따라서, 입력을 받으며 누적합(1부터 j까지의 부분배열의 합)을 갖는 배열 sum과 누적합의 최솟값(1부터 i까지의 부분 배열의 합)을 갖는 배열 min을 이용하여 문제를 해결하였다.

Code 1

언어 : JAVA

import java.util.Scanner;

class Solution {
    public static void main(String args[]) throws Exception {
        Scanner sc = new Scanner(System.in);
        int T;
        T = sc.nextInt();

        for (int tc = 1; tc <= T; tc++) {
            int N = sc.nextInt();
            int[] input = new int[N + 1];
            int[] sum = new int[N + 1];
            int[] min = new int[N + 1];

            for (int i = 1; i <= N; i++) {
                input[i] = sc.nextInt();
                sum[i] = sum[i - 1] + input[i];
                min[i] = sum[i] > min[i - 1] ? min[i - 1] : sum[i];
            }

            int max = sum[1];
            for (int i = 2; i <= N; i++) {
                if (max < sum[i] - min[i - 1])
                    max = sum[i] - min[i - 1];
            }
            System.out.println("#" + tc + " " + max);
        } // end of TC
        sc.close();
    }// end of main
}

Code 2

언어 : JAVA

import java.util.Scanner;

public class Solution {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int tc = 1; tc <= T; tc++) {
            int N = sc.nextInt();
            int[] A = new int[N];

            A[0] = sc.nextInt();

            int max = A[0];
            for (int i = 1; i < N; i++) {
                int num = sc.nextInt();
                A[i] = num;
                if (A[i - 1] + A[i] > A[i]) {
                    A[i] = A[i - 1] + A[i];
                }
                if (max < A[i]) {
                    max = A[i];
                }
            }

            System.out.println("#" + tc + " " + max);
        }
    }
}

[SWEA] 1240. 단순 2진 암호코드 D3 - Simulation

제출일 : 2019-11-16

문제 풀이 시간 : 1H

난이도 : ★★★

Problem

link : https://swexpertacademy.com/main/code/problem/problemSolver.do?contestProbId=AV15FZuqAL4CFAYD

Input

가장 첫줄은 전체 테스트 케이스의 수이다.

각 테스트 케이스의 첫 줄에 두 자연수가 주어지는데 각각 배열의 세로 크기 N, 배열의 가로크기 M이다 (1≤N<50, 1≤M<100).

그 다음 N개의 줄에는 M개의 배열의 값이 주어진다.

Output

각 테스트 케이스의 답을 순서대로 표준출력으로 출력하며, 각 케이스마다 줄의 시작에 “#C”를 출력하여야 한다.

이때 C는 케이스의 번호이다. 같은 줄에 빈칸을 하나 두고, 입력에 주어진 배열에서 정상적인 암호코드들에 포함된 숫자들의 합을 출력한다.

Example

input

2
16 80
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000011101101100010111011011000101100010001101001001101110110000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
11 70
00000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
00000001100101000110100011010111101101110010011001001101110110000000000
00000001100101000110100011010111101101110010011001001101110110000000000
00000001100101000110100011010111101101110010011001001101110110000000000
00000001100101000110100011010111101101110010011001001101110110000000000
00000001100101000110100011010111101101110010011001001101110110000000000
00000001100101000110100011010111101101110010011001001101110110000000000
00000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000

output

#1 38 
#2 0 

Solution & Inpression

인덱스 조작문제

입력에서 코드 값을 찾아 8개의 값을 구하기가 까다로운 문제였다.

전부 배열로 입력을 받았지만 문자열로 입력을 받아 비교하면 더 시간이 빠르지 않았을까 하는 생각도 든다.

Code

언어 : JAVA

메모리 : 28,036 kb

실행시간 : 156 ms

import java.io.FileInputStream;
import java.util.Arrays;
import java.util.Scanner;

public class Solution {
    static int N, M;
    static int[][] input;
    static int ans;
    static final int[][] code = { { 0, 0, 0, 1, 1, 0, 1 }// 0
            , { 0, 0, 1, 1, 0, 0, 1 }// 1
            , { 0, 0, 1, 0, 0, 1, 1 }// 2
            , { 0, 1, 1, 1, 1, 0, 1 }// 3
            , { 0, 1, 0, 0, 0, 1, 1 }// 4
            , { 0, 1, 1, 0, 0, 0, 1 }// 5
            , { 0, 1, 0, 1, 1, 1, 1 }// 6
            , { 0, 1, 1, 1, 0, 1, 1 }// 7
            , { 0, 1, 1, 0, 1, 1, 1 }// 8
            , { 0, 0, 0, 1, 0, 1, 1 }// 9
    };
    static int[] res;

    public static void main(String[] args) throws Exception {
        System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int tc = 1; tc <= T; tc++) {
            N = sc.nextInt();
            M = sc.nextInt();

            input = new int[8][7];
            boolean flag = false;
            for (int i = 0; i < N; i++) {
                String str = sc.next();
                for (int j = 0; j < M; j++) {
                    if (flag) // 이미 코드를 구한경우
                        break;

                    int tmp = str.charAt(j) - '0';
                    if (tmp == 1) {
                        flag = true;
                        j--;
                        for (int r = 0; r < 8; r++) {
                            for (int c = 0; c < 7; c++) {
                                input[r][c] = str.charAt(j++) - '0';
                            }
                        }
                    }
                }
            }

            getCode();
            System.out.println("#" + tc + " " + calc());

        } // end of TC
        sc.close();
    }// end of main

    private static int calc() {
        int result = (res[0] + res[2] + res[4] + res[6]) * 3 + (res[1] + res[3] + res[5]);
        if ((result + res[7]) % 10 == 0) {
            int sum = 0;
            for (int is : res) {
                sum += is;
            }
            return sum;
        } else
            return 0;
    }

    private static void getCode() {
        res = new int[8];
        Arrays.fill(res, -1);
        for (int k = 0; k < 10; k++) {
            for (int i = 0; i < 8; i++) {
                int flag = 0;
                for (int j = 0; j < 7; j++) {
                    if (input[i][j] == code[k][j])
                        flag++;
                }
                if (flag == 7)
                    res[i] = k;
            }
        }
        for (int i = 0; i < 8; i++) {
            if (res[i] == -1) {
                rotate();
                getCode();
                return;
            }
        }
    }

    private static void rotate() {
        int first = 0;
        for (int i = 0; i < 8; i++) {
            int[] tmp = input[i].clone();
            input[i][0] = first;
            for (int j = 1; j <= 6; j++) {
                input[i][j] = tmp[j - 1];
            }
            first = tmp[6];
        }
    }
}

[SWEA] 1961. 숫자 배열 회전 D2

제출일 : 2019-11-16

문제 풀이 시간 : 15M

난이도 : ★

Problem

link : https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5Pq-OKAVYDFAUq

Constraints

N은 3 이상 7 이하이다.

Input

가장 첫 줄에는 테스트 케이스의 개수 T가 주어지고, 그 아래로 각 테스트 케이스가 주어진다.

각 테스트 케이스의 첫 번째 줄에 N이 주어지고,

다음 N 줄에는 N x N 행렬이 주어진다.

Output

출력의 첫 줄은 '#t'로 시작하고,

다음 N줄에 걸쳐서 90도, 180도, 270도 회전한 모양을 출력한다.

입력과는 달리 출력에서는 회전한 모양 사이에만 공백이 존재함에 유의하라.

(t는 테스트 케이스의 번호를 의미하며 1부터 시작한다.)

Example

input

10
3
1 2 3
4 5 6
7 8 9
6
6 9 4 7 0 5
8 9 9 2 6 5
6 8 5 4 9 8
2 2 7 7 8 4
7 5 1 9 7 9
8 9 3 9 7 6
…

output

#1
741 987 369
852 654 258
963 321 147
#2
872686 679398 558496
952899 979157 069877
317594 487722 724799
997427 894586 495713
778960 562998 998259
694855 507496 686278
…

Solution & Inpression

인덱스 조작문제

행과 열의 계산이 익숙해지면 쉽게 해결 할 수 있는 문제

Code

언어 : JAVA

메모리 : 26,652 kb

실행시간 : 143 ms

import java.io.FileInputStream;
import java.util.Scanner;

public class Solution {
    static int N;
    static int[][] matrix;
    static int[][][] res;

    public static void main(String[] args) throws Exception {
        System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();
        for (int tc = 1; tc <= T; tc++) {
            System.out.println("#" + tc);

            N = sc.nextInt();
            matrix = new int[N][N];
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    matrix[i][j] = sc.nextInt();
                }
            }
            rotate();
            print();
        } // end of TC
    }// end of Main

    private static void print() {
        for (int i = 0; i < N; i++) {
            for (int k = 0; k < 3; k++) {
                for (int j = 0; j < N; j++) {
                    System.out.print(res[k][i][j]);
                }
                System.out.print(" ");
            }
            System.out.println();
        }
    }

    private static void rotate() {
        res = new int[3][N][N];
        for (int k = 0; k < 3; k++) {
            int r = 0, c = 0;
            for (int j = 0; j < N; j++) {
                for (int i = N - 1; i >= 0; i--) {
                    res[k][r][c++] = matrix[i][j];
                    if (c == N) {
                        r++;
                        c = 0;
                    }

                }
            }

            for (int i = 0; i < N; i++) {
                matrix[i] = res[k][i].clone();
            }
        }
    }
}

[SWEA] 4613. 러시아 국기 같은 깃발 D4 - Simulation

제출일 : 2019-11-16

문제 풀이 시간 : 20M

난이도 : ★★☆

Problem

link : https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWQl9TIK8qoDFAXj

input

첫 번째 줄에 테스트 케이스의 수 T가 주어진다.

각 테스트 케이스의 첫 번째 줄에는 두 정수 N,M(3≤N,M≤50)이 공백으로 구분되어 주어진다.

다음 N개의 줄에는 M개의 문자로 이루어진 문자열이 주어진다. i번 째 줄의 j번째 문자는 깃발에서 i번째 행 j번째 열인 칸의 색을 의미한다.

‘W’는 흰색, ‘B’는 파란색, ‘R’은 빨간색을 의미한다. ‘W’, ‘B’, ‘R’외의 다른 문자는 입력되지 않는다.

Output

각 줄마다 "#T" (T는 테스트 케이스 번호)를 출력한 뒤, 러시아 국기 같은 깃발을 만들기 위해서 새로 칠해야 하는 칸의 개수의 최솟값을 구하여 T 줄에 걸쳐서 출력한다.

Example

input

2
4 5
WRWRW
BWRWB
WRWRW
RWBWR
6 14
WWWWWWWWWWWWWW
WWRRWWBBBBBBWW
WRRRWWWBWWWWRB
WWBWBWWWBWRRRR
WBWBBWWWBBWRRW
WWWWWWWWWWWWWW

output

#1 11
#2 44

Solution & Inpression

가장 윗줄(0번)과 가장 아랫줄(N-1번)은 흰색과 빨간색으로 칠해져야 한다.

따라서 0~N-2까지의 수 중에서 2개의 수를 조합을 이용하여 뽑았는데 첫번째 숫자는 W로 칠해져야 하는 행의 숫자고 두번째 숫자는 B로 칠해져야 하는 행의 숫자이다.

이제 분할하여 색을 칠해줘야하는 경우를 세어 최소값을 구하면 된다.

Code

언어 : JAVA

메모리 : 28,928 kb

실행시간 : 175 ms

import java.io.FileInputStream;
import java.util.Scanner;

public class Solution {
    static int N, M;
    static char[][] map;
    static int ans;
    static int[] match;
    static boolean[] visit;

    public static void main(String[] args) throws Exception {
        System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int tc = 1; tc <= T; tc++) {
            N = sc.nextInt();
            M = sc.nextInt();
            map = new char[N][M];
            for (int i = 0; i < N; i++) {
                String str = sc.next();
                for (int j = 0; j < M; j++) {
                    map[i][j] = str.charAt(j);
                }
            }
            ans = Integer.MAX_VALUE;
            match = new int[2];
            visit = new boolean[N - 1];
            get(0, 0);

            System.out.println("#" + tc + " " + ans);
        }
    }

    private static void get(int start, int depth) {
        if (depth == 2) {
            solve();
            return;
        }
        for (int i = start; i < N - 1; i++) {
            if (!visit[i]) {
                visit[i] = true;
                match[depth] = i;
                get(i, depth + 1);
                visit[i] = false;
            }
        }

    }

    private static void solve() {
        int cnt = 0;
        // W
        for (int i = 0; i <= match[0]; i++) {
            for (int j = 0; j < M; j++) {
                if (map[i][j] != 'W')
                    cnt++;
            }
        }
        // B
        for (int i = match[0] + 1; i <= match[1]; i++) {
            for (int j = 0; j < M; j++) {
                if (map[i][j] != 'B')
                    cnt++;
            }
        }
        // R
        for (int i = match[1] + 1; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (map[i][j] != 'R')
                    cnt++;
            }
        }

        if (ans > cnt)
            ans = cnt;
    }
}

[SWEA] 4615. 재미있는 오셀로 게임 D3 - Simulation

제출일 : 2019-11-16

문제 풀이 시간 : 45M

난이도 : ★★☆

Problem

link : https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWQmA4uK8ygDFAXj

input

첫 번째 줄에 테스트 케이스의 수 T가 주어진다.

각 테스트 케이스의 첫 번째 줄에는 보드의 한 변의 길이 N과 플레이어가 돌을 놓는 횟수 M이 주어진다. N은 4, 6, 8 중 하나이다.

그 다음 M줄에는 돌을 놓을 위치와 돌의 색이 주어진다.

돌의 색이 1이면 흑돌, 2이면 백돌이다.

만약 3 2 1이 입력된다면 (3, 2) 위치에 흑돌을 놓는 것을 의미한다.

돌을 놓을 수 없는 곳은 입력으로 주어지지 않는다.

Output

각 테스트 케이스마다 게임이 끝난 후 보드 위의 흑돌, 백돌의 개수를 출력한다.

흑돌이 30개, 백돌이 34인 경우 30 34를 출력한다.

Example

input

10
5
0 1 1 0 0
0 0 1 0 3
0 1 0 1 0
0 0 0 0 0
1 0 5 0 0
5
0 0 1 1 0
0 0 1 0 2
0 0 0 1 0
0 1 0 0 0
1 0 5 0 0
…

output

#1 9
#2 8
…

Solution & Inpression

시뮬레이션 문제

예전에 한번 풀었던 문제여서 수월하게 풀수 있었다.

요즘 시뮬레이션 문제가 어렵게 느껴져 시뮬레이션 문제를 많이 풀어보려 생각중이다

항상 시뮬레이션 문제를 풀때는 문제를 정확히 읽고 요구사항대로 작성을 하면 되지만 쉬운일이 아니다.....

Code

언어 : JAVA

메모리 : 33,700 kb

실행시간 : 165 ms

import java.io.FileInputStream;
import java.util.Scanner;

public class Solution {
    static int N;// 보드 한변의 길이 (4, 6, 8 중 하나)
    static int M;// 플레이어가 돌을 놓는 횟수

    // 상, 하, 좌, 우, 좌상, 우하, 우상, 좌하
    static final int[] dr = { -1, 1, 0, 0, -1, 1, -1, 1 };
    static final int[] dc = { 0, 0, -1, 1, -1, 1, 1, -1 };

    static int[][] map;

    public static void main(String[] args) throws Exception {
        System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int tc = 1; tc <= T; tc++) {
            N = sc.nextInt();
            M = sc.nextInt();
            init();
            for (int i = 0; i < M; i++) {
                int r = sc.nextInt() - 1;
                int c = sc.nextInt() - 1;
                int player = sc.nextInt();// 1이면 흑돌 2이면 백돌
                put(r, c, player);
            }
            System.out.println("#" + tc + " " + sum());
        } // end of TC
        sc.close();
    }

    private static String sum() {
        int[] res = new int[2];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (map[i][j] == 1)
                    res[0]++;
                else if (map[i][j] == 2)
                    res[1]++;
            }
        }
        return res[0] + " " + res[1];
    }

    private static void init() {
        map = new int[N][N];
        int half = N / 2;
        map[half - 1][half] = 1;
        map[half][half - 1] = 1;
        map[half - 1][half - 1] = 2;
        map[half][half] = 2;
    }

    private static void put(int r, int c, int player) {
        map[r][c] = player;
        for (int dir = 0; dir < 8; dir++) {
            check(r, c, dir);
        }
    }

    private static void check(int r, int c, int dir) {
        int nr = r + dr[dir];
        int nc = c + dc[dir];

        while (true) {
            if (!isRange(nr, nc) || map[nr][nc] == 0)
                break;

            if (map[r][c] != map[nr][nc]) {
                nr += dr[dir];
                nc += dc[dir];
            } else
                break;
        }

        if (isRange(nr, nc) && map[nr][nc] == map[r][c]) {
            while (r != nr || c != nc) {
                map[nr][nc] = map[r][c];
                nr -= dr[dir];
                nc -= dc[dir];
            }
        }

    }

    private static boolean isRange(int r, int c) {
        if (0 <= r && r < N && 0 <= c && c < N)
            return true;
        return false;
    }
}