각 위치 i에 대해
Di=Xi−Yi
라고 하자. 여기서 문자를 정수로 보아 0은 0, 1은 1로 생각한다. 그러면 Di는 −1,0,1 중 하나이다.
먼저 목적식을 Di로 바꾸자. S의 앞 i글자에 포함된 1의 개수를 oneS(i)라고 하면,
fS(i)=oneS(i)−(i−oneS(i))=2oneS(i)−i
이다. 따라서
fX(i)−fY(i)=2(oneX(i)−oneY(i))=2j=1∑iDj
이다. 그러므로 전체 목적식은
2i=1∑Nj=1∑iDj=2j=1∑NDj(N−j+1)
이다.
이제 연산이 D에 어떤 영향을 주는지 보자. 구간 [l,r]에서 X와 Y의 1 개수가 같다는 것은
i=l∑rDi=0
이라는 뜻이다. 이 구간을 서로 바꾸면, 해당 구간의 모든 Di는 부호가 바뀐다. 즉 Di가 1이면 −1이 되고, −1이면 1이 되며, 0은 그대로 0이다.
따라서 문제는 다음과 같이 바뀐다.
Di∈{−1,0,1}인 수열이 있다. 합이 0인 연속구간의 부호를 원하는 만큼 뒤집을 수 있다. 이때
i=1∑NDi(N−i+1)
를 최대화하여라.
Di=0인 위치는 어떤 연산을 해도 계속 0이다. 이제 Di=0인 위치들만 보자. 만약 어떤 두 비영 위치 사이에 −1이 먼저 나오고, 그 뒤에 1이 나오며 그 사이가 모두 0이라면, 그 전체 구간의 합은 0이다. 이 구간을 뒤집으면
−1, 0, 0, …, 0, 1
이
1, 0, 0, …, 0, −1
이 된다. 즉 비영 위치들만 보면 인접한 −1,1을 1,−1로 바꿀 수 있다.
이 연산을 반복하면, Di=0인 위치들에서 모든 1을 앞쪽으로, 모든 −1을 뒤쪽으로 보낼 수 있다. 또한 연산은 1의 개수와 −1의 개수를 바꾸지 않으므로, 이보다 더 앞쪽에 1을 많이 놓을 수는 없다.
가중치 N−i+1은 i가 작을수록 크다. 따라서 최적 상태는 다음과 같다.
- Di=0인 위치들을 왼쪽부터 모은다.
- 그중 앞에서부터 원래 Di=1이었던 개수만큼 1을 배치한다.
- 나머지 비영 위치에는 −1을 배치한다.
- Di=0인 위치는 계속 0이다.
따라서 구현은 간단하다. Di=0인 위치들을 배열에 저장하고, Di=1인 개수를 P라고 하자. 비영 위치 배열을 pos라고 하면 최댓값은
2t=0∑P−1(N−post)−t=P∑∣pos∣−1(N−post)
이다. 여기서 구현에서는 post를 0-indexed 위치로 저장했기 때문에 가중치가 N−post가 된다.
시간 복잡도는 O(N)이고, 메모리 복잡도는 O(N)이다.