Table of Contents

ExplanationImplementation

Official Analysis (C++)

Explanation

Let's define freq(l,r,x)\texttt{freq}(l, r, x) as the number of times the value xx shows up in the range [l,r][l, r].

Our answer, at a minimum, will be freq(1,n,c)\texttt{freq}(1, n, c), if we don't perform an operation. Thus, our goal is to find a subarray that will maximize the additional occurrences of cc we can add to our answer.

If we want to transform all occurrences of a value vv into cc, then the contribution to our answer will be

freq(l,r,v)freq(l,r,c)\texttt{freq}(l, r, v) - \texttt{freq}(l, r, c)

because any value of cc will get disturbed by the operation needed to transform vv into cc. Now, our goal is to find the optimal tuple (l,r,v)(l, r, v) and add that to our minimum answer.

Consider all elements vv, where we transform vv into cc, and try to find our best subarray that way. Note that in an optimal subarray [l,r][l, r], we only consider subarrays where a[l]=a[r]=va[l] = a[r] = v, which makes it so that across all values of vv, there are only O(n)\mathcal{O}(n) endpoints to consider.

Considering we want to find the maximum answer across all subarrays, this hints towards transforming our problem into something similar to the classic max-subarray problem, which was covered in the prefix sums module.

Let's define ll to be the sorted array of all occurrences of vv in our array aa, and have bb be the array we run our max-subarray algorithm on, where l[i]l[i] directly corresponds to b[i]b[i]. Initially, every element in b[i]b[i] is set to 11. Now, to handle occurrences of cc in a possible subarray, we compress the intervals between each value of ll. More specifically, we perform the following operation for all valid ii:

b[i]=freq(l[i1]+1,l[i]1,c).b[i] \mathrel{-}= \texttt{freq}(l[i - 1] + 1, l[i] - 1, c).

With this transformation, we can apply our max-subarray algorithm of choice to get our answer.

Directly implementing the approach above is enough to pass all test cases, and is the implementation featured in the official editorial. The implementation below uses the same idea as the approach described above, but is modified to be considerably more concise.

Recall Kadane's algorithm for the max-subarray sum. The idea is to sweep from left to right, and for every index find the best subarray ending at said index. The greedy strategy is as follows:

  • If we are at index ii, and the previous max subarray ending at i1i-1 is less than zero, we cut it off and start a new array with the singular element at ii
  • Otherwise, we extend the subarray from i1i-1 by appending the current element to it

Our DP algorithm works in a similar way. Consider sweeping left to right, and having dp[v]\texttt{dp}[v] equal the number of occurrences of vv in our current prefix, while also keeping a counter for the number of times we encounter cc. Then, for this prefix, the countribution for this prefix would be dp[v]freq(1,i,c)\texttt{dp}[v] - \texttt{freq}(1, i, c), if we are currently at index ii.

However, it's not always optimal to take the entire prefix when transforming certain occurrences of vv into cc. More specifically, if dp[v]<freq(1,i,c)\texttt{dp}[v] < \texttt{freq}(1, i, c), then we should cut off this current prefix and start a new subarray. Thus, our DP state transition is

dp[v]=max(dp[v],freq(1,i,c))+1.\texttt{dp}[v] = \max(\texttt{dp}[v], \texttt{freq}(1, i, c)) + 1.

With this, we can calculate the best contribution as being the maximum value of dp[a[i]]freq(1,i,c)\texttt{dp}[a[i]] - \texttt{freq}(1, i, c), as we sweep from left to right.

Implementation

Time Complexity: O(N)\mathcal{O}(N)

C++

#include <bits/stdc++.h>
constexpr int MAX = 5e5;
int dp[MAX + 1];
int main() {
int n, c;
std::cin >> n >> c;
int num_c = 0;

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!