https://www.acmicpc.net/problem/10986

 

10986번: 나머지 합

수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j)

www.acmicpc.net

코드설명

누적합과 수학(나머지) 문제입니다.

 

문제조건을 보면, O(N^2)를 활용하여 진행할시 시간초과가 발생합니다.

 

수학(나머지)를 활용하여 진행합니다.

( (prefixSum[j] - prefixSum[i] ) % M == 0) 인값을 구하는것이 목표입니다.

위의 식을 전개할시

( (prefixSum[j] % M) - prefixSum[i] % M ) == 0)

prefixSum[j] % M == prefixSum[i] % M 일 경우, i ~ j 구간합이 M으로 나눌경우 0 이라는 것을 알 수 있습니다.

 

즉, 나머지값이 같은 구간합의 개수 중 2개를 뽑아서 각각 다 더하면 된다는 것입니다.

나머지(prefixSumRemian[1])가 1일경우의 구간합의 개수를 모두 구하고,

나머지(prefixSumRemian[2])가 2일경우의 구간합의 개수를 모두 구하고,

...

..

 

한뒤, prefixSumRemian[1]에서 2가지를 구해주는 nCr 공식을 통하여서 값을 구해줍니다.

nCr = (n!) / r!(n-r!) 에 의하여

nC2 일경우 (n) * (n-1) / 2 입니다.

 

코드

prefixSum 배열없이 바로 함수로 처리한 코드입니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, M;
public static long[] prefixSum;
public static long[] prefixSumRemian;
public static long answer = 0;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
prefixSum = new long[N+1];
prefixSumRemian = new long[M];
long sumValue = 0;
st = new StringTokenizer(br.readLine());
for(int i=0;i<N;i++) {
sumValue += Integer.parseInt(st.nextToken());
int remainder = (int) (sumValue % M);
prefixSumRemian[remainder] += 1; //나머지 개수를 세서 1씩 증가시킵니다.
}
answer += prefixSumRemian[0];
for(int i=0;i<M;i++) {
answer += prefixSumRemian[i] * (prefixSumRemian[i] - 1) / 2; // N*(N-1) / 2
}
System.out.println(answer);
}
}

 

prefixSum 배열로 prefixSum[1 ~ N]를 통해 처리한 코드입니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, M;
public static int[] arr;
public static long[] prefixSum;
public static long[] prefixSumRemian;
public static long answer = 0;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
arr = new int[N];
prefixSum = new long[N+1];
prefixSumRemian = new long[M];
long sumValue = 0;
st = new StringTokenizer(br.readLine());
for(int i=0;i<N;i++) {
sumValue += Integer.parseInt(st.nextToken());
prefixSum[i+1] = sumValue;
}
for(int i=1;i<=N;i++) {
int remainder = (int) (prefixSum[i] % M);
prefixSumRemian[remainder] += 1; //나머지 개수를 세서 1씩 증가시킵니다.
}
answer += prefixSumRemian[0];
for(int i=0;i<M;i++) {
answer += prefixSumRemian[i] * (prefixSumRemian[i] - 1) / 2; // N*(N-1) / 2
}
System.out.println(answer);
}
}

 

시간초과 ( O(N^2)의 연산이 들어가있습니다. )

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, M;
public static int[] arr;
public static int[] prefixSum;
public static int answer = 0;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
arr = new int[N];
prefixSum = new int[N+1];
int sumValue = 0;
st = new StringTokenizer(br.readLine());
for(int i=0;i<N;i++) {
arr[i] = Integer.parseInt(st.nextToken());
sumValue += arr[i];
prefixSum[i+1] = sumValue;
}
for(int i=0;i<=N;i++) {
for(int j=i+1;j<=N;j++) {
sumValue = prefixSum[j] - prefixSum[i];
if(sumValue % M == 0) answer += 1;
}
}
System.out.println(answer);
}
}

+ Recent posts