ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 초급반 3주차 풀이 - 반복문, 배열, 누적합
    ALOHA - 2022/ALOHA - 초급반 (2022 1학기) 2022. 5. 3. 10:15

    A. [2438] 별 찍기 - 1 (Bronze III)

    더보기

    반복문 예제로 항상 나오는 '별 찍기'에 왔습니다.

    \( i \)번째 줄에는 별을 \( i \)개 찍어주면 됩니다.

    void Main(){
    	int n; scanf("%d", &n);
    	for (int i = 1; i <= n; i++){
    		for (int j = 1; j <= i; j++){ printf("*"); }
    		printf("\n");
    	}
    }

    1. [2440] 별 찍기 - 3 (Bronze III)

    더보기

    \( i \)번째 줄에는 별을 \( N-i+1 \)개 찍어주면 됩니다.

    void Main(){
    	int n; scanf("%d", &n);
    	for (int i = 1; i <= n; i++){
    		for (int j = 1; j <= n-i+1; j++){ printf("*"); }
    		printf("\n");
    	}
    }
    더보기

    A. [2438] 별 찍기 - 1을 찍고, 이런 생각을 해봅시다. 'i를 n에서 1로 떨어뜨린다면?'

    그럼 1. [2440] 별 찍기 - 3의 정답이 됩니다.

    void Main(){
    	int n; scanf("%d", &n);
    	for (int i = n; i >= 1; i--){
    		for (int j = 1; j <= i; j++){ printf("*"); }
    		printf("\n");
    	}
    }

    2. [4344] 평균은 넘겠지 (Bronze I)

    더보기

    평균을 구한 뒤, 그 평균보다 큰 점수를 받은 학생의 수를 세주면 됩니다.

    '크거나 같은'이 아님에 주의하세요.

    int arr[1020];
    
    void Main(){
    	int t; scanf("%d", &t);
    	while (t--){
    		int n; scanf("%d", &n);
    		for (int i = 1; i <= n; i++){ scanf("%d", &arr[i]); }
    		double avg = 0;
    		for (int i = 1; i <= n; i++){ avg += arr[i]; }
    		avg /= n; int cnt = 0;
    		for (int i = 1; i <= n; i++){
    			if (avg < arr[i]){ cnt += 1; }
    		}
    		printf("%.3f%%\n", 100.0 * cnt/n);
    	}
    }

    3. [11659] 구간 합 구하기 4 (Silver IV)

    더보기

    누적합으로 구해줄 수 있습니다.

    \( PRF_{i} := \sum_{k=1}^{i} A_{k} \)로 두면, \( PRF_{i} = PRF_{i-1} + A_{i} \)이므로 계산도 빠르게 할 수 있고,

    \( \sum_{k=l}^{r} A_{k} = PRF_{r} - PRF_{l-1} \)이니 문제의 답도 빠르게 구할 수 있습니다.

    ll arr[100020], prf[100020];
    
    void Main(){
    	int n, q; scanf("%d %d", &n, &q);
    	for (int i = 1; i <= n; i++){ scanf("%d", &arr[i]); }
    	for (int i = 1; i <= n; i++){ prf[i] = prf[i-1] + arr[i]; }
    	while (q--){
    		int l, r; scanf("%d %d", &l, &r);
    		printf("%lld\n", prf[r] - prf[l-1]);
    	}
    }

    4. [2439] 별 찍기 - 2 (Bronze III)

    더보기

    이번에는 오른쪽으로 정렬된 별을 찍어야 합니다... 또는 공백과 별을 같이 찍어야 합니다.

    \( i \)번째 줄에는 공백 \( N-i \)개와 별 \( i \)개를 찍어주면 됩니다.

    void Main(){
    	int n; scanf("%d", &n);
    	for (int i = 1; i <= n; i++){
    		for (int j = 1; j <= n-i; j++){ printf(" "); }
    		for (int j = 1; j <= i; j++){ printf("*"); }
    		printf("\n");
    	}
    }

    5. [2442] 별 찍기 - 5 (Bronze III)

    더보기

    \( i \)번째 줄에 찍어야 하는 공백은 \( N-i \)개입니다. (공백만 두고 보면 4. [2439] 별 찍기 - 2와 동일)

    그리고 \( i \)번째 줄에 찍어야 하는 별은 \( 2i - 1\)개입니다. (문제에서 알려줌)

    void Main(){
    	int n; scanf("%d", &n);
    	for (int i = 1; i <= n; i++){
    		for (int j = 1; j <= n-i; j++){ printf(" "); }
    		for (int j = 1; j <= 2*i-1; j++){ printf("*"); }
    		printf("\n");
    	}
    }

    6. [2852] NBA 농구 (Silver III)

    더보기

    일단 아래 배열들을 정의합시다.

    \( A_{i} := \) 경기 시작 \( i \)초 후에 1번 팀이 골을 넣었는가?

    \( B_{i} := \) 경기 시작 \( i \)초 후 2번 팀이 골을 넣었는가?

    \( PA_{i} := \) 경기 시작 \( i \)초 후 1번 팀의 득점 상황

    \( PB_{i} := \) 경기 시작 \( i \)초 후 2번 팀의 득점 상황

     

    이제 득점이 들어올 때마다 그에 맞는 배열과 시간에 1을 더해둔 뒤,

    입력이 끝났을 때 PA와 PB를 A와 B의 누적합으로 구해주면 됩니다.

     

    1번 팀이 이기던 시간은 \( PA_{i} \gt PB_{i} \)인 \( i \)의 개수,

    2번 팀이 이기던 시간은 \( PA_{i} \lt PB_{i} \)인 \( i \)의 개수로 구해줄 수 있습니다.

    입력과 출력 과정이 약간 복잡함에 주의하세요. [TODO: C언어로 코드 작성]

    const int T = 48*60;
    pi2 arr[T+20];
    
    void prt(int t){
    	cout << t/600 << t/60%10 << ":" << t/10%6 << t%10;
    }
    
    void Main(){
    	int n; cin >> n;
    	for (int i = 1; i <= n; i++){
    		int x; string t; cin >> x >> t;
    		int m = (t[0]-'0')*10 + t[1]-'0';
    		int s = (t[3]-'0')*10 + t[4]-'0';
    		int tim = 60*m + s;
    		for (int p = tim; p < T; p++){
    			if (x == 1){ arr[p].fr += 1; } else{ arr[p].sc += 1; }
    		}
    	}
    	int t1 = 0, t2 = 0;
    	for (int i = 0; i < T; i++){
    		if (arr[i].fr > arr[i].sc){ t1 += 1; }
    		if (arr[i].fr < arr[i].sc){ t2 += 1; }
    	}
    	prt(t1); cout << endl; prt(t2);
    }

    7. [2559] 수열 (Silver III)

    더보기

    구간의 합을 구해야 하니 일단 누적합을 넣어봅시다.

    \( PRF_{i} := \sum_{k=1}^{i} A_{k} \)

     

    이제 답을 생각해봅시다.

    연속적인 \( K \)일간의 온도의 합은 \( \sum_{p=i}^{i+K-1} A_{p} \)로 나타낼 수 있고,

    \( \sum_{p=i}^{i+K-1} A_{p} = PRF_{i+K-1} - PRF_{i-1} \)로 나타낼 수 있습니다.

    그러니 \( \max_{1 \le i \le i+K-1 \le N} (PRF_{i+K-1} - PRF_{i-1}) \)을 구해주면 됩니다.

    int arr[100020], prf[100020];
    
    void Main(){
    	int n, k; scanf("%d %d", &n, &k);
    	for (int i = 1; i <= n; i++){ scanf("%d", &arr[i]); }
    	for (int i = 1; i <= n; i++){ prf[i] = prf[i-1] + arr[i]; }
    	int ans = -1e9;
    	for (int i = 1; i+k-1 <= n; i++){
    		int res = prf[i+k-1] - prf[i-1];
    		if (ans < res){ ans = res; }
    	}
    	printf("%d", ans);
    }

    8. [10211] Maximum Subarray (Silver III)

    더보기

    일단 문제에서 주어진 식을 구간합을 사용하여 바꿔봅시다.

    \( PRF_{i} := \sum_{k=1}^{i} A_{k} \)

    \( \max_{1 \le i \le j \le N} (A_{i} + A_{i+1} + \cdots + \A_{j}) = \max_{1 \le i \le j \le N} (PRF_{j} - PRF_{i-1}) \)

    이제 저대로 구현해주면 됩니다.

    int arr[1020], prf[1020];
    
    void Main(){
    	int t; scanf("%d", &t);
    	while (t--){
    		int n, k; scanf("%d", &n);
    		for (int i = 1; i <= n; i++){ scanf("%d", &arr[i]); }
    		for (int i = 1; i <= n; i++){ prf[i] = prf[i-1] + arr[i]; }
    		int ans = -1e9;
    		for (int i = 1; i <= n; i++){
    			for (int j = i; j <= n; j++){
    				int res = prf[j] - prf[i-1];
    				if (ans < res){ ans = res; }
    			}
    		}
    		printf("%d\n", ans);
    	}
    }
    더보기

    사실 이 문제는 누적합 없이도 풀 수 있습니다.

    \( i \)에서 시작해서 \( j \)를 한 칸씩 옮길 때마다 합을 갱신해주고,

    최종 답은 위 과정에서 나왔던 모든 합 중 하나가 됩니다.

    int arr[1020];
    
    void Main(){
    	int t; scanf("%d", &t);
    	while (t--){
    		int n; scanf("%d", &n);
    		for (int i = 1; i <= n; i++){ scanf("%d", &arr[i]); }
    		int ans = -1e9;
    		for (int i = 1; i <= n; i++){
    			int res = 0;
    			for (int j = i; j <= n; j++){
    				res += arr[j];
    				if (ans < res){ ans = res; }
    			}
    		}
    		printf("%d\n", ans);
    	}
    }

    9. [11660] 구간 합 구하기 5 (Silver III)

    더보기

    이젠 2차원 누적합 문제입니다. 그러니 일단 누적합을 정의해봅시다.

    \( PRF_{i, j} := \) \( \sum_{y=1}^{i} \sum_{x=1}^{j} A_{y, x} \)

     

    위와 같이 저장하면 2차원 누적합은 그리 어렵지 않게 해결할 수 있는데, '포함-배제의 원리'를 사용하면 됩니다.

    \( \sum_{y=y_{1}}^{y_{2}} \sum_{x=x_{1}}^{x_{2}} A_{y, x} = PRF_{y_{2}, x_{2}} - PRF_{y_{2}, x_{1}-1} - PRF_{y_{1}-1, x_{2}} + PRF_{y_{1}-1, x_{1}-1} \)

     

    누적합을 직접 그려보면 간단히 이해할 수 있습니다. [TODO: 그림 추가]

    이제 그대로 짜면 될 것 같지만, 위 정의대로 PRF를 구현했다가는 PRF 구하는 과정에서 TLE가 나게 됩니다.

    그러니, \( PRF_{i, j} \)를 아래 식으로 구해줘야 합니다. (위에 있던 쿼리 식이랑 비교해보세요.)

    \( PRF_{i, j} = A_{i, j} + PRF_{i, j-1} + PRF_{i-1, j} - PRF_{i-1, j-1} \)

    ll arr[1030][1030], prf[1030][1030];
    
    int main(){
    	int n, q; scanf("%d %d", &n, &q);
    	for (int i = 1; i <= n; i++){
    		for (int j = 1; j <= n; j++){ scanf("%d", &arr[i][j]); }
    	}
    	for (int i = 1; i <= n; i++){
    		for (int j = 1; j <= n; j++){
    			prf[i][j] = arr[i][j] + prf[i][j-1] + prf[i-1][j] - prf[i-1][j-1];
    		}
    	}
    	while (q--){
    		int y1, y2, x1, x2; cin >> y1 >> x1 >> y2 >> x2;
    		y1 -= 1; x1 -= 1;
    		printf("%lld\n", prf[y2][x2] - prf[y2][x1] - prf[y1][x2] + prf[y1][x1]);
    	}
    }
Designed by Tistory.