Predominant Frequency Division
Description:â
You are given an array consisting of the numbers 1, 2, and 3. Check whether it is possible to split it into three contiguous non-empty parts such that, for each part from 1 to 3, the following condition holds:
- the number of elements greater than is at most half of the part.
In other words, you need to divide the array into three pairwise disjoint contiguous non-empty parts so that in the left part the number of ones is at least the total number of twos and threes, in the middle part the total number of ones and twos is at least the number of threes, and the right part can be anything, but it must be non-empty.
Input Each test contains multiple test cases. The first line contains the number of test cases (). The description of the test cases follows.
The first line of each test case contains an integer () â the length of the array. The second line of each test case contains integers ().
Output For each test case, print "YES" if there exists a way to split the array as required, and "NO" otherwise.
Video Explanation:â
Approaches:â
1. Prefix Sum Optimization (Optimal)â
To split the array into three contiguous parts (), we can simplify the mathematical conditions:
- Condition for :
count(1) >= count(2) + count(3). If we assign to1s and to2s and3s, the prefix sum of must be . - Condition for :
count(1) + count(2) >= count(3). If we assign to1s and2s, and to3s, the sum of this segment must be . - Condition for : Simply needs to be non-empty.
Instead of testing all possible split points, we can use prefix sums to do this in :
- Let be the prefix sum from index to using the weights for the second condition (where
1s and2s are ,3s are ). - The sum for the middle segment (from index to ) is calculated as . We need this to be , which means .
- To maximize our chances of finding a valid for a given , we should precalculate the maximum possible to the right of . We create an array
max_P2_rightwheremax_P2_right[i+1]holds the maximum for all . (Note: because must have at least one element). - As we iterate to find the end of (index ), we maintain the running sum for Condition 1. If the running sum is and , we have found a valid split!
Complexityâ
- Time Complexity: per testcase, where is the length of the array. We scan the array to build the prefix sums and then do a single pass to check the conditions.
- Space Complexity: auxiliary space to store the prefix sums and the
max_P2_rightarray.
Solutions:â
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> a(n);
vector<int> p2(n);
int current_p2 = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
current_p2 += (a[i] != 3 ? 1 : -1);
p2[i] = current_p2;
}
// Precalculate the maximum P2 values from the right
vector<int> max_p2_right(n);
max_p2_right[n - 2] = p2[n - 2];
for (int i = n - 3; i >= 1; i--) {
max_p2_right[i] = max(p2[i], max_p2_right[i + 1]);
}
int p1 = 0;
bool possible = false;
// Iterate to find a valid split point for P1 (index i)
for (int i = 0; i < n - 2; i++) {
p1 += (a[i] == 1 ? 1 : -1);
if (p1 >= 0 && p2[i] <= max_p2_right[i + 1]) {
possible = true;
break;
}
}
if (possible) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
int main() {
// Fast I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
java
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
if (scanner.hasNextInt()) {
int t = scanner.nextInt();
while (t-- > 0) {
solve(scanner);
}
}
scanner.close();
}
private static void solve(Scanner scanner) {
int n = scanner.nextInt();
int[] a = new int[n];
int[] p2 = new int[n];
int currentP2 = 0;
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
currentP2 += (a[i] != 3 ? 1 : -1);
p2[i] = currentP2;
}
int[] maxP2Right = new int[n];
maxP2Right[n - 2] = p2[n - 2];
for (int i = n - 3; i >= 1; i--) {
maxP2Right[i] = Math.max(p2[i], maxP2Right[i + 1]);
}
int p1 = 0;
boolean possible = false;
for (int i = 0; i < n - 2; i++) {
p1 += (a[i] == 1 ? 1 : -1);
if (p1 >= 0 && p2[i] <= maxP2Right[i + 1]) {
possible = true;
break;
}
}
if (possible) {
System.out.println("YES");
} else {
System.out.println("NO");
}
}
}
Python
import sys
def solve():
input_data = sys.stdin.read().split()
if not input_data:
return
t = int(input_data[0])
idx = 1
for _ in range(t):
n = int(input_data[idx])
idx += 1
a = [int(x) for x in input_data[idx : idx + n]]
idx += n
p2 = [0] * n
current_p2 = 0
for i in range(n):
current_p2 += 1 if a[i] != 3 else -1
p2[i] = current_p2
max_p2_right = [0] * n
max_p2_right[n - 2] = p2[n - 2]
for i in range(n - 3, 0, -1):
max_p2_right[i] = max(p2[i], max_p2_right[i + 1])
p1 = 0
possible = False
for i in range(n - 2):
p1 += 1 if a[i] == 1 else -1
if p1 >= 0 and p2[i] <= max_p2_right[i + 1]:
possible = True
break
if possible:
print("YES")
else:
print("NO")
if __name__ == "__main__":
solve()
JavaScript
const fs = require('fs');
function main() {
const input = fs.readFileSync(0, 'utf-8').trim().split(/\s+/);
if (input.length === 0 || input[0] === '') return;
let t = parseInt(input[0], 10);
let idx = 1;
for (let i = 0; i < t; i++) {
let n = parseInt(input[idx++], 10);
let a = [];
for (let j = 0; j < n; j++) {
a.push(parseInt(input[idx++], 10));
}
let p2 = new Int32Array(n);
let currentP2 = 0;
for (let j = 0; j < n; j++) {
currentP2 += (a[j] !== 3 ? 1 : -1);
p2[j] = currentP2;
}
let maxP2Right = new Int32Array(n);
maxP2Right[n - 2] = p2[n - 2];
for (let j = n - 3; j >= 1; j--) {
maxP2Right[j] = Math.max(p2[j], maxP2Right[j + 1]);
}
let p1 = 0;
let possible = false;
for (let j = 0; j < n - 2; j++) {
p1 += (a[j] === 1 ? 1 : -1);
if (p1 >= 0 && p2[j] <= maxP2Right[j + 1]) {
possible = true;
break;
}
}
if (possible) {
console.log("YES");
} else {
console.log("NO");
}
}
}
main();
Completed working through this block? Sync progress to workspace.