Yaroslav and Productivity
Description:â
Yaroslav's productivity during the day is described by an array of length . His productivity can be negative if he watches short videos, or positive if he works. The total productivity is defined as the sum of all values in the array.
Sometimes Yaroslav reads motivational posts. He has posts, where the -th post has an impact value . If Yaroslav reads a post with value , then all productivity values from the beginning of the day up to position change sign, that is, all integers are multiplied by .
What is the maximum possible total productivity Yaroslav can achieve by reading any (possibly none) of the posts?
Input The first line contains a single integer () â the number of test cases. The first line of each test case contains two integers and () â the number of measurements and the number of motivational posts. The second line contains integers () â the productivity values. The third line contains integers () â the impact values of the posts. It is guaranteed that all are distinct.
Output For each test case, output a single integer â the maximum possible total productivity.
Video Explanation:â
Approaches:â
1. Block Independence (Optimal)â
At first glance, it seems that reading a post and flipping a prefix affects many elements simultaneously, creating a complex dependency chain. However, we can break this down by partitioning the array into "blocks".
First, let's sort the allowed prefix operations in ascending order such that . This naturally splits our array into blocks:
- Block 1: Elements from to
- Block 2: Elements from to
- ... and so on.
- Final Block: Elements from to .
Notice what happens when we apply an operation at : it flips the signs of all blocks from Block 1 up to Block . Because we can choose to apply or not apply the operation at , and this choice uniquely toggles the sign of Block relative to all subsequent blocks, we can independently choose the final sign (positive or negative) of every single block from to .
Since their signs can be chosen completely independently, the optimal strategy to maximize the sum is simply to take the absolute value of the sum of each block! (Note: Elements after the maximum value, which is , can never be flipped. Their signs remain permanently fixed).
Algorithm:
- Sort the array in ascending order.
- Iterate through the blocks defined by the boundaries in .
- For each block, calculate its sum, and add the absolute value of this sum to our total.
- For the remaining elements after the last boundary in , calculate their sum and add it to our total without taking the absolute value (since their signs are fixed).
Complexityâ
- Time Complexity: per testcase because we must sort the array . The subsequent iterations to sum the blocks take linear time.
- Space Complexity: or auxiliary space depending on the language's sort implementation and input storage.
Solutions:â
C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<long long> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<int> b(m);
for (int i = 0; i < m; i++) {
cin >> b[i];
}
// Sort the prefix operations
sort(b.begin(), b.end());
long long total_sum = 0;
int last_idx = 0;
// Calculate max possible sum for each block (independent signs)
for (int i = 0; i < m; i++) {
long long block_sum = 0;
for (int j = last_idx; j < b[i]; j++) {
block_sum += a[j];
}
total_sum += std::abs(block_sum);
last_idx = b[i];
}
// Elements after the maximum allowed prefix can never be flipped
long long rest_sum = 0;
for (int j = last_idx; j < n; j++) {
rest_sum += a[j];
}
total_sum += rest_sum;
cout << total_sum << "\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;
import java.util.Arrays;
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 m = scanner.nextInt();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextLong();
}
int[] b = new int[m];
for (int i = 0; i < m; i++) {
b[i] = scanner.nextInt();
}
// Sort the prefix operations
Arrays.sort(b);
long totalSum = 0;
int lastIdx = 0;
// Calculate max possible sum for each block (independent signs)
for (int i = 0; i < m; i++) {
long blockSum = 0;
for (int j = lastIdx; j < b[i]; j++) {
blockSum += a[j];
}
totalSum += Math.abs(blockSum);
lastIdx = b[i];
}
// Elements after the maximum allowed prefix can never be flipped
long restSum = 0;
for (int j = lastIdx; j < n; j++) {
restSum += a[j];
}
totalSum += restSum;
System.out.println(totalSum);
}
}
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])
m = int(input_data[idx+1])
idx += 2
a = [int(x) for x in input_data[idx : idx + n]]
idx += n
b = [int(x) for x in input_data[idx : idx + m]]
idx += m
# Sort the prefix operations
b.sort()
total_sum = 0
last_idx = 0
# Calculate max possible sum for each block (independent signs)
for i in range(m):
block_sum = sum(a[last_idx:b[i]])
total_sum += abs(block_sum)
last_idx = b[i]
# Elements after the maximum allowed prefix can never be flipped
total_sum += sum(a[last_idx:n])
print(total_sum)
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 m = parseInt(input[idx++], 10);
let a = [];
for (let j = 0; j < n; j++) {
a.push(Number(input[idx++]));
}
let b = [];
for (let j = 0; j < m; j++) {
b.push(parseInt(input[idx++], 10));
}
// Sort the prefix operations
b.sort((x, y) => x - y);
let totalSum = 0n;
let lastIdx = 0;
// Calculate max possible sum for each block (independent signs)
for (let j = 0; j < m; j++) {
let blockSum = 0n;
for (let k = lastIdx; k < b[j]; k++) {
blockSum += a[k];
}
// Adding absolute value of BigInt
totalSum += blockSum < 0n ? -blockSum : blockSum;
lastIdx = b[j];
}
// Elements after the maximum allowed prefix can never be flipped
for (let k = lastIdx; k < n; k++) {
totalSum += a[k];
}
console.log(totalSum.toString());
}
}
main();
Completed working through this block? Sync progress to workspace.