#include <iostream>
#include <map>
using namespace std;
int prefix[200001];
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n, k, num;
long long ans = 0;
map<int, long long> m; //m[i]=j: 누적합으로 i를 만들 수 있는 경우의 수=j
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> num;
prefix[i] = prefix[i - 1] + num;
if (prefix[i] == k) ans++;
}
for (int i = 1; i <= n; i++) {
ans += m[prefix[i] - k];
m[prefix[i]]++; //1~i의 누적합
}
cout << ans;
return 0;
}
n을 20만까지 허용하므로 구간합을 모두 구하면 시간초과가 난다.
따라서 누적합으로 숫자를 만드는 경우의 수를 저장하는 map을 사용하여 문제를 해결해야 한다.
우선 값을 입력받으면서 1~i번째의 구간합이 k이면 그 경우를 추가한다.
그 후
k=arr[i]-arr[j-1]->arr[j-1]=arr[i]-k이므로 이를 성립시키는 j를 찾으면 된다.
예를 한번 들어보자.
4 0
2 -2 2 -2
위의 입력이 주어졌다.
i=1: 누적합에 2가 들어가고, k와 다르므로 넘어간다.
ans+=m[prefix[i]-k]에서 ans+=m[2-0]
m[prefix[i]]++에서 m[2]++가 된다. 1~1번째의 구간합이다.
i=2: 누적합 prefix[2]=0이 되고, k와 같으므로 ans++(1)이 된다.
ans+=m[prefix[i]-k]에서 ans+=m[0-0]=0
m[prefix[i]]++에서 m[0]++(1)이 된다. 1~2번째의 구간합이다.
i=3: 누적합 prefix[3]=2가 되고, k와 다르므로 넘어간다.
ans+=m[prefix[i]-k]에서 ans+=m[2-0]=m[2]=1
즉, 인덱스 3 이전으로 구간합을 구하는 과정에서 구간합이 k임을 성립시키는 j가 존재하는 것이다.(2~3의 구간합)
m[prefix[i]]++에서 m[2]++가 된다. 1-3번째의 구간합이다.
i=4: 누적합 prefix[4]=0이 되고, k와 같으므로 ans++(3)
ans+=m[prefix[i]-k]에서 ans+=m[0-0]=m[0]=1->ans=4
즉, 인덱스 4 이전으로 구간합을 구하는 과정에서 구간합이 k임을 성립시키는 j가 존재하는 것이다.(3~4의 구간합)
m[prefix[i]]++에서 m[0]++가 된다. 1-4번째의 구간합이다.
위의 과정을 거쳐 4가 출력되는 것이다.
ps. 이해하는데 정말 오래 걸렸다. 나중에 다시 한 번 보자
'Coding Test' 카테고리의 다른 글
백준 17609 회문 (1) | 2024.05.19 |
---|---|
백준 2224 명제 증명 (0) | 2024.05.18 |
백준 14621 나만 안되는 연애 (0) | 2024.04.13 |
백준 21275 폰 호석만 (0) | 2024.04.12 |
백준 15787 백준 기차가 어둠을 헤치고 (0) | 2024.04.11 |