LogIn
I don't have account.
Sponsored -55%
Tarkan Top Brand

Tarkan Portable Folding Laptop Desk with Drawer, Cup & Tablet Holder (Black)

Foldable · Anti-slip strip · 60 × 40 cm · No assembly

★★★★★ 4.2 (7,877) 1K+ bought last month
₹899 M.R.P. ₹1,999Save ₹1,100
Buy Now
Adℹ

Maximum Productivity After Employee Rearrangement | Dynamic Programming Assignment Problem

HackFury
47 Views

#greedy

#dynamic-programming

Amazon Pay offer
Adℹ

You are given an array A of length N, where:

  • A[i] represents the productivity score of the employee initially sitting at seat i (1-indexed).
  • Before the workday begins, the manager can perform exactly one global rearrangement of all employees.
  • Every employee must be assigned to a unique seat.

If an employee originally sitting at position x is moved to position y, that employee contributes:

A[x] × ∣x − y∣

to the team's total productivity score.

Your task is to determine the maximum possible productivity score after rearranging all employees.

Constraints

  • 2 ≤ N ≤ 2000
  • 1 ≤ A[i] ≤ 10^9

Understanding the Problem

Suppose we have:


Position : 1  2  3
Value    : 1  3  2

Employee at position 2 has productivity 3. If we move him from position 2 to position 1:


Contribution = 3 × |2 - 1|
             = 3 × 1
             = 3

Similarly, every employee contributes:

Productivity × Distance Moved

The goal is to maximize:

Σ(Productivity × Distance)

by choosing the best final arrangement.

Brute Force Approach

A straightforward idea would be:

  • Generate all permutations of employees.
  • Calculate total productivity for each arrangement.
  • Return the maximum.

For N = 2000, this is impossible. Number of permutations: 2000! which is astronomically large.

We need a smarter observation.

Key Insight

Consider two employees:

  • Employee A → productivity = 1000
  • Employee B → productivity = 5

Moving Employee A by 10 seats gives:

1000 × 10 = 10000

Moving Employee B by 10 seats gives:

5 × 10 = 50

Clearly, high-productivity employees should get the largest movement distances.

This suggests: Process employees in descending order of productivity.

Important Observation

After sorting employees by productivity, suppose we place the most productive employee first.

Where should we place him?

To maximize distance, the best positions are: Leftmost seat or Rightmost seat

For every highly productive employee, we only need to decide: Put him on the left end? or Put him on the right end? This dramatically reduces the search space.

1: Understanding What We Need to Maximize

Each employee starts at a fixed position and has a productivity value associated with them. If an employee originally sitting at position x is moved to position y, their contribution to the final answer becomes:

Productivity×∣x−y∣

The distance moved by the employee is multiplied by their productivity value. This means that moving a highly productive employee even a small distance can contribute more than moving a low-productivity employee a large distance.

Our objective is to rearrange all employees in such a way that the sum of these contributions is maximized.

2: Sorting Employees Is the Key Observation

Consider two employees:


Employee A → Productivity = 1000
Employee B → Productivity = 5

If both employees move by the same distance:

Employee A:

  • 1000 × 10 = 10000

Employee B:

  • 5 × 10 = 50

Clearly, moving Employee A is far more valuable. This tells us something important: The employees with larger productivity values should be given priority when choosing positions that produce large movement distances.

Therefore, instead of processing employees in their original order, we sort them in descending order of productivity and place the most valuable employees first.

Example


Suppose:

Position : 1  2  3  4
Value    : 8  3  5  1

Store:

(8,1)
(3,2)
(5,3)
(1,4)

where:

  • (Productivity, Original Position)

After sorting:


(8,1)
(5,3)
(3,2)
(1,4)

Now we process employees in this order.

3: Why Only the Leftmost and Rightmost Seats Matter

This is the most important observation of the problem. Suppose initially:


Seats: 1 2 3 4 5

We want to place the highest productivity employee.

Which position should we choose?

Possible choices:


Seat 1
Seat 2
Seat 3
Seat 4
Seat 5

Notice that the largest movement distance is always achieved by one of the extreme positions: Seat 1 or Seat 5

A middle seat can never provide a larger distance than an endpoint.

Therefore, when placing a highly productive employee, the only positions worth considering are: Leftmost available seat or Rightmost available seat

What Happens After One Placement?

Suppose we assign someone to seat 1. Now the seating arrangement looks like:

X 2 3 4 5

The remaining available seats are:

2 3 4 5

Again, for the next employee, the most useful choices are: Seat 2 or Seat 5

which are the two ends of the remaining interval. After another placement:

X 2 3 4 X

Remaining:

2 3 4

Again the next employee only needs to consider: Seat 2 or Seat 4

The same pattern continues throughout the process.

Important Conclusion

At every step: Current employee has only two choices:

  • Take the leftmost available seat.
  • Take the rightmost available seat.

This observation dramatically reduces the search space and makes Dynamic Programming possible.

4: Meaning of dp[i][left]

This is the most important part of the entire solution. Many people understand the transitions but get confused about what information the DP state is actually storing. We define:

dp[i][left]

as: The maximum productivity score that can be achieved after placing the first i employees from the sorted list (highest productivity employees first), where exactly left of those employees have been placed on the left side of the arrangement.

Notice that we are not storing the actual arrangement of employees inside the DP state. Doing that would make the state too large and impossible to compute efficiently. Instead, we only store how many employees have already been placed and how many of those placements were made from the left side.

The beauty of this approach is that this small amount of information is enough to reconstruct the current available seating interval. Once we know how many seats have been occupied from the left and right ends, we automatically know which seats are still free.

Example

Suppose:


N = 5
i = 3
left = 2

This means that we have already processed and placed the first 3 employees from the sorted list. Out of those three placements:

  • 2 employees were assigned from the left side.
  • Since a total of 3 employees have already been placed, the remaining placement must have come from the right side.
rightUsed = i - left
          = 3 - 2
          = 1

So our current situation is:

  • Left placements = 2
  • Right placements = 1

which means the seats must look like:


1  2  3  4  5
X  X  _  _  X

Even though we never stored this arrangement explicitly, we can derive it entirely from i and left.

5: Why Can We Calculate Remaining Seats From Only left?

At first glance, it may seem impossible to know which seats are still available without storing the complete seating arrangement. However, because employees are always assigned to one of the two ends of the remaining interval, the arrangement follows a very predictable structure.

Whenever we place an employee, we either consume the leftmost available seat or the rightmost available seat. As a result, occupied seats gradually grow inward from both ends, while the unoccupied seats always remain together in the middle.

Because of this property, knowing:

  • Total employees placed = i
  • Employees placed on left = left
  • automatically tells us: Employees placed on right = i - left

and therefore the exact interval of remaining seats.

This is why the DP state only needs two dimensions instead of storing the complete arrangement.

6: Finding the Next Available Left Seat

Once we know how many seats have already been occupied from the left side, determining the next available left seat becomes straightforward.

  • If: left = 2
  • then seats: 1 and 2 are already occupied.
  • Therefore, the next free seat on the left side must be: leftPos = left + 1; which gives: leftPos = 3

This formula works for every state because left-side placements always occur consecutively from the beginning of the array.

7: Finding the Next Available Right Seat

Similarly, once we know how many seats have been consumed from the right side, we can determine the next free seat on the right.

Suppose:

  • N = 5
  • rightUsed = 1
  • Then seat: 5 has already been occupied.
  • Therefore the next available right seat becomes: rightPos = N - rightUsed = 5 - 1 = 4

This formula works because right-side placements always occur consecutively from the end of the array.

8: Processing the Current Employee

Suppose the sorted employees are:


(8,1)
(5,3)
(3,2)
(1,4)

and we are currently processing:

(3,2)

This means:

  • Productivity = 3
  • Original Position = 2
  • Assume our DP state is: i = 2 and left = 1
  • This tells us: rightUsed = 1
  • and the current seat configuration is:
1 2 3 4
X _ _ X
  • The only available seats are: 2 and 3

Since every future arrangement must keep consuming seats from the ends of the remaining interval, these are the only two valid positions we need to consider.

9: Choice 1 – Place the Employee on the Left

If we assign the current employee to the leftmost available seat, he will be placed at: Seat 2 His movement distance becomes: |2 - 2| = 0 and therefore his contribution is: 3 × 0 = 0

Since we used one more seat from the left side, the number of left placements increases by one. This is why the next state becomes:

dp[i+1][left+1]

The DP transition adds the employee's contribution to the best score already achieved in the current state.


dp[i+1][left+1] =
max(
    dp[i+1][left+1],
    dp[i][left] +
    value * abs(pos - leftPos)
);

10: Choice 2 – Place the Employee on the Right

Instead of using the left seat, we may assign the employee to the rightmost available seat. That seat is: Seat 3 The movement distance becomes: |2 - 3| = 1 giving a contribution of: 3 × 1 = 3

Since the employee was placed on the right side, the count of left placements remains unchanged. Therefore the next state remains:

dp[i+1][left]

The DP compares this score with any previously computed value for the same state and keeps the maximum.


dp[i+1][left] =
max(
    dp[i+1][left],
    dp[i][left] +
    value * abs(pos - rightPos)
);

11: Why This DP Is Correct

The correctness of the solution comes from two fundamental observations.

  • First, employees are processed in descending order of productivity, ensuring that the most valuable employees get the first opportunity to occupy positions that generate large movement distances.

  • Second, after every placement, the remaining free seats always form one continuous interval. Because of this property, the next employee only needs to choose between the two endpoints of that interval. No other seat can produce a better arrangement that is not already represented by one of these choices.

The DP explores every possible sequence of left-end and right-end decisions. Since every valid final arrangement can be represented as a sequence of such decisions, the optimal arrangement is guaranteed to be considered. Therefore, the maximum value stored in the final DP row is the answer.

Complexity Analysis

  • Sorting: O(N log N)

  • DP States: O(N²)

  • Transition Cost: O(1)

  • Total Time Complexity: O(N²)

  • Space Complexity: O(N²)

This efficiently solves the problem for N ≤ 2000.

DP Visualization

  • Consider: N = 4
  • After placing two employees: Seats: [ X _ _ X ]
  • Used: left = 1 and right = 1
  • Remaining: [ _ _ ]
  • Next employee can only go: leftmost remaining seat or rightmost remaining seat
  • which preserves the DP structure.

#include <bits/stdc++.h>
using namespace std;

long long maximizeProductivity(int N, vector<long long>& A)
{
    vector<pair<long long, int>> employees;
    for (int i = 0; i < N; i++)
    {
        employees.push_back({A[i], i + 1});
    }
    sort(employees.begin(), employees.end(),
         [](const auto& a, const auto& b)
         {
             return a.first > b.first;
         });
    // Initialize unreachable DP states with a very small value.
    // Avoid using LLONG_MIN since adding to it may cause overflow.
    const long long NEG = -(1LL << 60);
    vector<vector<long long>> dp(
        N + 1,
        vector<long long>(N + 1, NEG));

    dp[0][0] = 0;
    for (int i = 0; i < N; i++)
    {
        auto [value, pos] = employees[i];
        for (int left = 0; left <= i; left++)
        {
            if (dp[i][left] == NEG)
                continue;
            int rightUsed = i - left;
            int leftPos = left + 1;
            int rightPos = N - rightUsed;
            // Place at left end
            dp[i + 1][left + 1] =
                max(dp[i + 1][left + 1],
                    dp[i][left] +
                    value * abs(pos - leftPos));
            // Place at right end
            dp[i + 1][left] =
                max(dp[i + 1][left],
                    dp[i][left] +
                    value * abs(pos - rightPos));
        }
    }

    long long answer = 0;
    for (int left = 0; left <= N; left++)
    {
        answer = max(answer, dp[N][left]);
    }
    return answer;
}

int main()
{
    int N;
    cin >> N;
    vector<long long> A(N);
    for (int i = 0; i < N; i++)
    {
        cin >> A[i];
    }
    cout << maximizeProductivity(N, A) << endl;
    return 0;
}

import java.util.*;

public class Main {

    public static long maximizeProductivity(int N, long[] A) {
        Employee[] employees = new Employee[N];
        for (int i = 0; i < N; i++) {
            employees[i] = new Employee(A[i], i + 1);
        }
        Arrays.sort(employees, (a, b) -> Long.compare(b.value, a.value));
        // Use a large negative value to represent unreachable DP states.
        // Avoid Long.MIN_VALUE directly, since adding to it can overflow.
        long NEG = Long.MIN_VALUE / 4;
        long[][] dp = new long[N + 1][N + 1];
        for (int i = 0; i <= N; i++) {
            Arrays.fill(dp[i], NEG);
        }
        dp[0][0] = 0;
        for (int i = 0; i < N; i++) {
            long value = employees[i].value;
            int pos = employees[i].position;
            for (int left = 0; left <= i; left++) {
                if (dp[i][left] == NEG)
                    continue;
                int rightUsed = i - left;
                int leftPos = left + 1;
                int rightPos = N - rightUsed;
                dp[i + 1][left + 1] = Math.max(
                        dp[i + 1][left + 1],
                        dp[i][left] + value * Math.abs(pos - leftPos));
                dp[i + 1][left] = Math.max(
                        dp[i + 1][left],
                        dp[i][left] + value * Math.abs(pos - rightPos));
            }
        }

        long answer = 0;
        for (int left = 0; left <= N; left++) {
            answer = Math.max(answer, dp[N][left]);
        }
        return answer;
    }

    static class Employee {
        long value;
        int position;
        Employee(long value, int position) {
            this.value = value;
            this.position = position;
        }
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        long[] A = new long[N];
        for (int i = 0; i < N; i++) {
            A[i] = sc.nextLong();
        }
        System.out.println(maximizeProductivity(N, A));
        sc.close();
    }
}

using System;
using System.Collections.Generic;

public class Program
{
    public static long MaximizeProductivity(int N, long[] A)
    {
        List<(long value, int pos)> employees = new();
        for (int i = 0; i < N; i++)
        {
            employees.Add((A[i], i + 1));
        }
        employees.Sort((a, b) => b.value.CompareTo(a.value));
        long NEG = long.MinValue / 4;
        long[,] dp = new long[N + 1, N + 1];
        for (int i = 0; i <= N; i++)
        {
            for (int j = 0; j <= N; j++)
            {
                dp[i, j] = NEG;
            }
        }
        dp[0, 0] = 0;
        for (int i = 0; i < N; i++)
        {
            long value = employees[i].value;
            int pos = employees[i].pos;
            for (int left = 0; left <= i; left++)
            {
                if (dp[i, left] == NEG)
                    continue;

                int rightUsed = i - left;
                int leftPos = left + 1;
                int rightPos = N - rightUsed;
                dp[i + 1, left + 1] = Math.Max(
                    dp[i + 1, left + 1],
                    dp[i, left] + value * Math.Abs(pos - leftPos));

                dp[i + 1, left] = Math.Max(
                    dp[i + 1, left],
                    dp[i, left] + value * Math.Abs(pos - rightPos));
            }
        }

        long answer = 0;
        for (int left = 0; left <= N; left++)
        {
            answer = Math.Max(answer, dp[N, left]);
        }
        return answer;
    }

    public static void Main()
    {
        int N = int.Parse(Console.ReadLine());
        long[] A = Array.ConvertAll(
            Console.ReadLine().Split(),
            long.Parse);
        Console.WriteLine(
            MaximizeProductivity(N, A));
    }
}

def maximizeProductivity(N, A):
    employees = []
    for i, value in enumerate(A):
        employees.append((value, i + 1))
    employees.sort(reverse=True)
    NEG = -10**30
    dp = [[NEG] * (N + 1) for _ in range(N + 1)]
    dp[0][0] = 0
    for i in range(N):
        value, pos = employees[i]
        for left in range(i + 1):
            if dp[i][left] == NEG:
                continue
            right_used = i - left
            left_pos = left + 1
            right_pos = N - right_used
            dp[i + 1][left + 1] = max(
                dp[i + 1][left + 1],
                dp[i][left] + value * abs(pos - left_pos)
            )

            dp[i + 1][left] = max(
                dp[i + 1][left],
                dp[i][left] + value * abs(pos - right_pos)
            )
    return max(dp[N])

def main():
    N = int(input())
    A = list(map(int, input().split()))

    print(maximizeProductivity(N, A))

if __name__ == "__main__":
    main()

Takeaways

This problem is a classic example of:

  • Dynamic Programming on permutations
  • Assignment optimization
  • Greedy ordering + DP
  • Interval DP / Left-Right placement DP

The crucial observation is that after sorting employees by productivity, every employee only needs to choose between the leftmost and rightmost available seat. This transforms an impossible N! permutation problem into an efficient O(N²) dynamic programming solution.

Responses (0)

Write a response

CommentHide Comments

No Comments yet.

"},"4":{"id":4,"name":"ZEBRONICS Blanc mouse ad","otherData":"{}","contentFormat":2,"content":"
Sponsored -53%
Zebronics #1 Best Seller

ZEBRONICS Blanc Slim Wireless Mouse — Rechargeable, BT + 2.4GHz (Black)

Up to 1600 DPI · Silent clicks · 63g · Multicolor LED

★★★★★ 4.0 (9,512) 5K+ bought last month
₹376 M.R.P. ₹799Save ₹423
Buy Now
"},"2":{"id":2,"name":"Crousal Ads","otherData":"{}","contentFormat":2,"content":"
Sponsored -34%
iQOO Amazon's Choice

iQOO Z10 Lite 5G — Cyber Green, 4GB RAM, 128GB Storage

Dimensity 6300 · 50MP Sony AI Camera · 6000 mAh · IP64

★★★★★ 4.0 (2,052) 500+ bought last month
₹18,997 M.R.P. ₹28,999Save ₹10,002
Buy Now
"},"1":{"id":1,"name":"Banner Ads","otherData":"{}","contentFormat":2,"content":"\n
\n \n \n \"Amazon\n \n
"}}},"blogDetails":{"isWriter":false,"likes":0,"isLikedByUser":false,"tagIds":[17,65,66,133,177],"tags":[{"id":17,"name":"Array","maskingName":"array","isFeatured":true},{"id":65,"name":"Greedy","maskingName":"greedy","isFeatured":false},{"id":66,"name":"Dynamic Programming","maskingName":"dynamic-programming","isFeatured":false},{"id":133,"name":"Coding Problems","maskingName":"coding-problems","isFeatured":true},{"id":177,"name":"DSA","maskingName":"dsa","isFeatured":true}],"comments":[],"bookmark":{"isBookmarked":false,"count":0},"author":{"userId":"MjlfNF84LVs0XTJuLXRDX0FOZ2VfX0l0","name":"HackFury"},"viewCount":46,"showBannerImage":false,"seoTags":"dynamic programming, dp on permutations, assignment optimization, interval dp, left right placement dp, employee rearrangement problem, productivity maximization, competitive programming, algorithm explanation, dp state design, dp transitions, sorting and dp, greedy plus dp, optimization problem, permutation dp, coding interview problem, programming contest solution, O(N squared solution, array rearrangement, maximize score, productivity score calculation, dynamic programming tutorial, algorithm design, cpp solution, java solution, python solution, csharp solution, dp visualization, interval a","content":"

You are given an array A of length N, where:

\n\n

If an employee originally sitting at position x is moved to position y, that employee contributes:

\n
A[x] × ∣x − y∣\n
\n

to the team's total productivity score.

\n

Your task is to determine the maximum possible productivity score after rearranging all employees.

\n

Constraints

\n\n

Understanding the Problem

\n

Suppose we have:

\n
\nPosition : 1  2  3\nValue    : 1  3  2\n
\n

Employee at position 2 has productivity 3. If we move him from position 2 to position 1:

\n
\nContribution = 3 × |2 - 1|\n             = 3 × 1\n             = 3\n
\n

Similarly, every employee contributes:

\n
Productivity × Distance Moved\n
\n

The goal is to maximize:

\n
Σ(Productivity × Distance)\n
\n

by choosing the best final arrangement.

\n

Brute Force Approach

\n

A straightforward idea would be:

\n\n

For N = 2000, this is impossible. Number of permutations: 2000! which is astronomically large.

\n

We need a smarter observation.

\n

Key Insight

\n

Consider two employees:

\n\n

Moving Employee A by 10 seats gives:

\n
1000 × 10 = 10000\n
\n

Moving Employee B by 10 seats gives:

\n
5 × 10 = 50\n
\n

Clearly, high-productivity employees should get the largest movement distances.

\n

This suggests: Process employees in descending order of productivity.

\n

Important Observation

\n

After sorting employees by productivity, suppose we place the most productive employee first.

\n

Where should we place him?

\n

To maximize distance, the best positions are: Leftmost seat or Rightmost seat

\n

For every highly productive employee, we only need to decide: Put him on the left end? or Put him on the right end? This dramatically reduces the search space.

\n

1: Understanding What We Need to Maximize

\n

Each employee starts at a fixed position and has a productivity value associated with them. If an employee originally sitting at position x is moved to position y, their contribution to the final answer becomes:

\n
Productivity×∣x−y∣\n
\n

The distance moved by the employee is multiplied by their productivity value. This means that moving a highly productive employee even a small distance can contribute more than moving a low-productivity employee a large distance.

\n

Our objective is to rearrange all employees in such a way that the sum of these contributions is maximized.

\n

2: Sorting Employees Is the Key Observation

\n

Consider two employees:

\n
\nEmployee A → Productivity = 1000\nEmployee B → Productivity = 5\n
\n

If both employees move by the same distance:

\n

Employee A:

\n\n

Employee B:

\n\n

Clearly, moving Employee A is far more valuable. This tells us something important: The employees with larger productivity values should be given priority when choosing positions that produce large movement distances.

\n

Therefore, instead of processing employees in their original order, we sort them in descending order of productivity and place the most valuable employees first.

\n

Example

\n
\nSuppose:\n\nPosition : 1  2  3  4\nValue    : 8  3  5  1\n\nStore:\n\n(8,1)\n(3,2)\n(5,3)\n(1,4)\n
\n

where:

\n\n

After sorting:

\n
\n(8,1)\n(5,3)\n(3,2)\n(1,4)\n
\n

Now we process employees in this order.

\n

3: Why Only the Leftmost and Rightmost Seats Matter

\n

This is the most important observation of the problem. Suppose initially:

\n
\nSeats: 1 2 3 4 5\n
\n

We want to place the highest productivity employee.

\n

Which position should we choose?

\n

Possible choices:

\n
\nSeat 1\nSeat 2\nSeat 3\nSeat 4\nSeat 5\n
\n

Notice that the largest movement distance is always achieved by one of the extreme positions: Seat 1 or Seat 5

\n

A middle seat can never provide a larger distance than an endpoint.

\n

Therefore, when placing a highly productive employee, the only positions worth considering are: Leftmost available seat or Rightmost available seat

\n

What Happens After One Placement?

\n

Suppose we assign someone to seat 1. Now the seating arrangement looks like:

\n
X 2 3 4 5\n
\n

The remaining available seats are:

\n
2 3 4 5\n
\n

Again, for the next employee, the most useful choices are: Seat 2 or Seat 5

\n

which are the two ends of the remaining interval. After another placement:

\n
X 2 3 4 X\n
\n

Remaining:

\n
2 3 4\n
\n

Again the next employee only needs to consider: Seat 2 or Seat 4

\n

The same pattern continues throughout the process.

\n

Important Conclusion

\n

At every step: Current employee has only two choices:

\n\n

This observation dramatically reduces the search space and makes Dynamic Programming possible.

\n

4: Meaning of dp[i][left]

\n

This is the most important part of the entire solution. Many people understand the transitions but get confused about what information the DP state is actually storing. We define:

\n
dp[i][left]\n
\n

as: The maximum productivity score that can be achieved after placing the first i employees from the sorted list (highest productivity employees first), where exactly left of those employees have been placed on the left side of the arrangement.

\n

Notice that we are not storing the actual arrangement of employees inside the DP state. Doing that would make the state too large and impossible to compute efficiently. Instead, we only store how many employees have already been placed and how many of those placements were made from the left side.

\n

The beauty of this approach is that this small amount of information is enough to reconstruct the current available seating interval. Once we know how many seats have been occupied from the left and right ends, we automatically know which seats are still free.

\n

Example

\n

Suppose:

\n
\nN = 5\ni = 3\nleft = 2\n
\n

This means that we have already processed and placed the first 3 employees from the sorted list. Out of those three placements:

\n\n
rightUsed = i - left\n          = 3 - 2\n          = 1\n
\n

So our current situation is:

\n\n

which means the seats must look like:

\n
\n1  2  3  4  5\nX  X  _  _  X\n
\n

Even though we never stored this arrangement explicitly, we can derive it entirely from i and left.

\n

5: Why Can We Calculate Remaining Seats From Only left?

\n

At first glance, it may seem impossible to know which seats are still available without storing the complete seating arrangement. However, because employees are always assigned to one of the two ends of the remaining interval, the arrangement follows a very predictable structure.

\n

Whenever we place an employee, we either consume the leftmost available seat or the rightmost available seat. As a result, occupied seats gradually grow inward from both ends, while the unoccupied seats always remain together in the middle.

\n

Because of this property, knowing:

\n\n

and therefore the exact interval of remaining seats.

\n

This is why the DP state only needs two dimensions instead of storing the complete arrangement.

\n

6: Finding the Next Available Left Seat

\n

Once we know how many seats have already been occupied from the left side, determining the next available left seat becomes straightforward.

\n\n

This formula works for every state because left-side placements always occur consecutively from the beginning of the array.

\n

7: Finding the Next Available Right Seat

\n

Similarly, once we know how many seats have been consumed from the right side, we can determine the next free seat on the right.

\n

Suppose:

\n\n

This formula works because right-side placements always occur consecutively from the end of the array.

\n

8: Processing the Current Employee

\n

Suppose the sorted employees are:

\n
\n(8,1)\n(5,3)\n(3,2)\n(1,4)\n
\n

and we are currently processing:

\n
(3,2)\n
\n

This means:

\n\n
1 2 3 4\nX _ _ X\n
\n\n

Since every future arrangement must keep consuming seats from the ends of the remaining interval, these are the only two valid positions we need to consider.

\n

9: Choice 1 – Place the Employee on the Left

\n

If we assign the current employee to the leftmost available seat, he will be placed at: Seat 2 His movement distance becomes: |2 - 2| = 0 and therefore his contribution is: 3 × 0 = 0

\n

Since we used one more seat from the left side, the number of left placements increases by one. This is why the next state becomes:

\n
dp[i+1][left+1]\n
\n

The DP transition adds the employee's contribution to the best score already achieved in the current state.

\n
\ndp[i+1][left+1] =\nmax(\n    dp[i+1][left+1],\n    dp[i][left] +\n    value * abs(pos - leftPos)\n);\n
\n

10: Choice 2 – Place the Employee on the Right

\n

Instead of using the left seat, we may assign the employee to the rightmost available seat. That seat is: Seat 3 The movement distance becomes: |2 - 3| = 1 giving a contribution of: 3 × 1 = 3

\n

Since the employee was placed on the right side, the count of left placements remains unchanged. Therefore the next state remains:

\n
dp[i+1][left]\n
\n

The DP compares this score with any previously computed value for the same state and keeps the maximum.

\n
\ndp[i+1][left] =\nmax(\n    dp[i+1][left],\n    dp[i][left] +\n    value * abs(pos - rightPos)\n);\n
\n

11: Why This DP Is Correct

\n

The correctness of the solution comes from two fundamental observations.

\n\n

The DP explores every possible sequence of left-end and right-end decisions. Since every valid final arrangement can be represented as a sequence of such decisions, the optimal arrangement is guaranteed to be considered. Therefore, the maximum value stored in the final DP row is the answer.

\n

Complexity Analysis

\n\n

This efficiently solves the problem for N ≤ 2000.

\n

DP Visualization

\n\n
\n#include <bits/stdc++.h>\nusing namespace std;\n\nlong long maximizeProductivity(int N, vector<long long>& A)\n{\n    vector<pair<long long, int>> employees;\n    for (int i = 0; i < N; i++)\n    {\n        employees.push_back({A[i], i + 1});\n    }\n    sort(employees.begin(), employees.end(),\n         [](const auto& a, const auto& b)\n         {\n             return a.first > b.first;\n         });\n    // Initialize unreachable DP states with a very small value.\n    // Avoid using LLONG_MIN since adding to it may cause overflow.\n    const long long NEG = -(1LL << 60);\n    vector<vector<long long>> dp(\n        N + 1,\n        vector<long long>(N + 1, NEG));\n\n    dp[0][0] = 0;\n    for (int i = 0; i < N; i++)\n    {\n        auto [value, pos] = employees[i];\n        for (int left = 0; left <= i; left++)\n        {\n            if (dp[i][left] == NEG)\n                continue;\n            int rightUsed = i - left;\n            int leftPos = left + 1;\n            int rightPos = N - rightUsed;\n            // Place at left end\n            dp[i + 1][left + 1] =\n                max(dp[i + 1][left + 1],\n                    dp[i][left] +\n                    value * abs(pos - leftPos));\n            // Place at right end\n            dp[i + 1][left] =\n                max(dp[i + 1][left],\n                    dp[i][left] +\n                    value * abs(pos - rightPos));\n        }\n    }\n\n    long long answer = 0;\n    for (int left = 0; left <= N; left++)\n    {\n        answer = max(answer, dp[N][left]);\n    }\n    return answer;\n}\n\nint main()\n{\n    int N;\n    cin >> N;\n    vector<long long> A(N);\n    for (int i = 0; i < N; i++)\n    {\n        cin >> A[i];\n    }\n    cout << maximizeProductivity(N, A) << endl;\n    return 0;\n}\n
\nimport java.util.*;\n\npublic class Main {\n\n    public static long maximizeProductivity(int N, long[] A) {\n        Employee[] employees = new Employee[N];\n        for (int i = 0; i < N; i++) {\n            employees[i] = new Employee(A[i], i + 1);\n        }\n        Arrays.sort(employees, (a, b) -> Long.compare(b.value, a.value));\n        // Use a large negative value to represent unreachable DP states.\n        // Avoid Long.MIN_VALUE directly, since adding to it can overflow.\n        long NEG = Long.MIN_VALUE / 4;\n        long[][] dp = new long[N + 1][N + 1];\n        for (int i = 0; i <= N; i++) {\n            Arrays.fill(dp[i], NEG);\n        }\n        dp[0][0] = 0;\n        for (int i = 0; i < N; i++) {\n            long value = employees[i].value;\n            int pos = employees[i].position;\n            for (int left = 0; left <= i; left++) {\n                if (dp[i][left] == NEG)\n                    continue;\n                int rightUsed = i - left;\n                int leftPos = left + 1;\n                int rightPos = N - rightUsed;\n                dp[i + 1][left + 1] = Math.max(\n                        dp[i + 1][left + 1],\n                        dp[i][left] + value * Math.abs(pos - leftPos));\n                dp[i + 1][left] = Math.max(\n                        dp[i + 1][left],\n                        dp[i][left] + value * Math.abs(pos - rightPos));\n            }\n        }\n\n        long answer = 0;\n        for (int left = 0; left <= N; left++) {\n            answer = Math.max(answer, dp[N][left]);\n        }\n        return answer;\n    }\n\n    static class Employee {\n        long value;\n        int position;\n        Employee(long value, int position) {\n            this.value = value;\n            this.position = position;\n        }\n    }\n\n    public static void main(String[] args) {\n\n        Scanner sc = new Scanner(System.in);\n        int N = sc.nextInt();\n        long[] A = new long[N];\n        for (int i = 0; i < N; i++) {\n            A[i] = sc.nextLong();\n        }\n        System.out.println(maximizeProductivity(N, A));\n        sc.close();\n    }\n}\n
\nusing System;\nusing System.Collections.Generic;\n\npublic class Program\n{\n    public static long MaximizeProductivity(int N, long[] A)\n    {\n        List<(long value, int pos)> employees = new();\n        for (int i = 0; i < N; i++)\n        {\n            employees.Add((A[i], i + 1));\n        }\n        employees.Sort((a, b) => b.value.CompareTo(a.value));\n        long NEG = long.MinValue / 4;\n        long[,] dp = new long[N + 1, N + 1];\n        for (int i = 0; i <= N; i++)\n        {\n            for (int j = 0; j <= N; j++)\n            {\n                dp[i, j] = NEG;\n            }\n        }\n        dp[0, 0] = 0;\n        for (int i = 0; i < N; i++)\n        {\n            long value = employees[i].value;\n            int pos = employees[i].pos;\n            for (int left = 0; left <= i; left++)\n            {\n                if (dp[i, left] == NEG)\n                    continue;\n\n                int rightUsed = i - left;\n                int leftPos = left + 1;\n                int rightPos = N - rightUsed;\n                dp[i + 1, left + 1] = Math.Max(\n                    dp[i + 1, left + 1],\n                    dp[i, left] + value * Math.Abs(pos - leftPos));\n\n                dp[i + 1, left] = Math.Max(\n                    dp[i + 1, left],\n                    dp[i, left] + value * Math.Abs(pos - rightPos));\n            }\n        }\n\n        long answer = 0;\n        for (int left = 0; left <= N; left++)\n        {\n            answer = Math.Max(answer, dp[N, left]);\n        }\n        return answer;\n    }\n\n    public static void Main()\n    {\n        int N = int.Parse(Console.ReadLine());\n        long[] A = Array.ConvertAll(\n            Console.ReadLine().Split(),\n            long.Parse);\n        Console.WriteLine(\n            MaximizeProductivity(N, A));\n    }\n}\n
\ndef maximizeProductivity(N, A):\n    employees = []\n    for i, value in enumerate(A):\n        employees.append((value, i + 1))\n    employees.sort(reverse=True)\n    NEG = -10**30\n    dp = [[NEG] * (N + 1) for _ in range(N + 1)]\n    dp[0][0] = 0\n    for i in range(N):\n        value, pos = employees[i]\n        for left in range(i + 1):\n            if dp[i][left] == NEG:\n                continue\n            right_used = i - left\n            left_pos = left + 1\n            right_pos = N - right_used\n            dp[i + 1][left + 1] = max(\n                dp[i + 1][left + 1],\n                dp[i][left] + value * abs(pos - left_pos)\n            )\n\n            dp[i + 1][left] = max(\n                dp[i + 1][left],\n                dp[i][left] + value * abs(pos - right_pos)\n            )\n    return max(dp[N])\n\ndef main():\n    N = int(input())\n    A = list(map(int, input().split()))\n\n    print(maximizeProductivity(N, A))\n\nif __name__ == \"__main__\":\n    main()\n
\n

Takeaways

\n

This problem is a classic example of:

\n\n

The crucial observation is that after sorting employees by productivity, every employee only needs to choose between the leftmost and rightmost available seat. This transforms an impossible N! permutation problem into an efficient O(N²) dynamic programming solution.

","categoryId":133,"subCategoryId":133,"contentFormat":5,"blogId":133,"userId":"MjlfNF84LVs0XTJuLXRDX0FOZ2VfX0l0","title":"Maximum Productivity After Employee Rearrangement | Dynamic Programming Assignment Problem","url":"maximum-productivity-after-employee-rearrangement-dynamic-programming-assignment-problem","bannerImage":"","seoDescription":"Maximize team productivity after employee rearrangement using Dynamic Programming. Learn the key observation, DP state design, transitions, and O(N²) solution.","generatedOn":"2026-06-08T13:42:17","updatedOn":"2026-06-08T13:42:17"},"popularContents":[{"id":35,"title":"Cursor vs Copilot : Which AI Coding Assistant Wins in 2025?","url":"cursor-vs-copilot-which-ai-coding-assistant-truly-wins-in-2025","description":null,"seoDescription":"Compare Cursor vs GitHub Copilot on speed, context awareness, multi-file support, pricing and code quality to choose the best AI coding assistant for developers","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212323Z","viewCount":0},{"id":168,"title":"Amazon SDE-2 Interview Experience (3 Years Experience)","url":"amazon-sde-2-interview-experience-3-years-experience","description":null,"seoDescription":" Read a real Amazon SDE-2 interview experience covering the online assessment, coding rounds, object-oriented design, leadership principles and system design.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212428Z","viewCount":0},{"id":138,"title":"DSA Patterns for Coding Interviews: Complete LeetCode Roadmap (Beginner to Advanced)","url":"dsa-patterns-for-coding-interviews-complete-leetcode-roadmap-beginner-to-advanced","description":null,"seoDescription":"Master every LeetCode pattern for coding interviews. Learn Arrays, Sliding Window, Graphs, Dynamic Programming, Trees, Heaps and more with 250+ curated problem","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212411Z","viewCount":0},{"id":175,"title":"American Express (AMEX) Online Assessment Experience (2026) | 3 Coding Questions","url":"american-express-amex-online-assessment-experience-2026-3-coding-questions","description":null,"seoDescription":"Read my American Express Online Assessment 2026 experience with 3 coding questions, C# solutions, approaches, difficulty analysis and preparation tips.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212455Z","viewCount":0},{"id":83,"title":"Uber SDE 2 Interview Experience (5 Rounds, Selected) - Complete DSA Questions with solution, System Design & Managerial Round","url":"uber-sde-2-interview-experience","description":null,"seoDescription":"Uber SDE 2 interview experience with 5 rounds, real DSA questions, system design, coding round, and preparation tips to crack Uber interviews.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212365Z","viewCount":0},{"id":213,"title":"Amazon SDE II Interview Experience (Bangalore, Selected) ~ Aug 2026","url":"amazon-sde-ii-interview-experience-bangalore-selected-aug-2026","description":null,"seoDescription":"Amazon SDE II interview experience from Bangalore covering 4 rounds, DSA, LLD, system design, Leadership Principles, coding questions and selection.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212469Z","viewCount":0},{"id":135,"title":"Spinny SDE-1 Interview Experience (Selected)","url":"spinny-sde-1-interview-experience-selected","description":null,"seoDescription":"Spinny SDE-1 Interview Experience (Selected) | 4 Rounds Breakdown: Coding, LLD, Java, SQL + Real Interview Questions","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212398Z","viewCount":0},{"id":130,"title":"Rippling SDE-2 Interview Experience (4+ Years Experience) | Offer Received | Coding, LLD & System Design","url":"rippling-sde-2-interview-experience-4-years-experience-offer-received-coding-lld-system-design","description":null,"seoDescription":"Detailed Rippling SDE-2 interview experience with complete 5 rounds, coding questions, rules engine design, system design and preparation tips.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1212382Z","viewCount":0},{"id":166,"title":"System Design Interview – BIGGEST Mistakes to Avoid","url":"system-design-interview-biggest-mistakes-to-avoid","description":null,"seoDescription":"Learn the biggest mistakes to avoid in a system design interview, from unclear requirements to poor trade-off analysis. Includes real-world cases, advanced insights and examples to help you ace your next system design interview.","contentType":2,"generatedOn":"2026-10-07T01:30:25.118254Z","viewCount":0},{"id":165,"title":"Top 50+ SQL Interview Questions and Answers for Intermediate to Advanced","url":"top-sql-interview-questions-and-answers-for-intermediate-to-advanced","description":null,"seoDescription":"Top SQL Interview Questions and Answers for Intermediate to Advanced. Top SQL Interview Questions for experience. Frequently asked SQL interview questions with answers","contentType":2,"generatedOn":"2026-10-07T01:30:25.1182491Z","viewCount":0}],"latestContents":[{"id":219,"title":"6 Tools That Made My Life Easier as a Software Engineer","url":"6-tools-that-made-my-life-easier-as-a-software-engineer","description":null,"seoDescription":"The 6 developer tools I use daily as a software engineer: Git, VS Code, Docker, Postman, Chrome DevTools, and AI assistants, with real tips, mistakes, and trade","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531143Z","viewCount":0},{"id":218,"title":"When Should a Business Use Multiple AI Agents Instead of One?","url":"when-should-a-business-use-multiple-ai-agents-instead-of-one","description":null,"seoDescription":"Single agent or multi-agent AI? Learn the 4 signals that justify splitting agents by knowledge, permissions, and risk, plus routing and handoff tips.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531197Z","viewCount":0},{"id":216,"title":"AI in Clinical Trials Market Estimated to Experience a Hike in Growth by 2035","url":"ai-in-clinical-trials-market-estimated-to-experience-a-hike-in-growth-by-2035","description":null,"seoDescription":"The exclusive information about market dynamics serves as a valuable guide to predict economic scenarios and initiatives taken to enhance future growth. Our mar","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531212Z","viewCount":0},{"id":217,"title":"AI in Clinical Trials Market Estimated to Experience a Hike in Growth by 2035","url":"ai-in-clinical-trials-market-estimated-to-experience-a-hike-in-growth-by-2035","description":null,"seoDescription":"The exclusive information about market dynamics serves as a valuable guide to predict economic scenarios and initiatives taken to enhance future growth. Our mar","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531227Z","viewCount":0},{"id":215,"title":"What Happens When an AI Agent Doesn't Know the Answer?","url":"what-happens-when-an-ai-agent-doesnt-know-the-answer","description":null,"seoDescription":"Most AI agents fail quietly. They guess instead of saying \"I don't know.\" Here's how to design better fallback and human-handoff behavior.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531274Z","viewCount":0},{"id":214,"title":"Greedy Algorithms Explained: How They Work, When They Fail and How to Use Them","url":"greedy-algorithms-explained-how-they-work-when-they-fail-and-how-to-use-them","description":null,"seoDescription":"Learn greedy algorithms step by step with C# code Dijkstra, Huffman coding, knapsack and MSTs plus when greedy fails and how to prove it's correct","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531291Z","viewCount":0},{"id":213,"title":"Amazon SDE II Interview Experience (Bangalore, Selected) ~ Aug 2026","url":"amazon-sde-ii-interview-experience-bangalore-selected-aug-2026","description":null,"seoDescription":"Amazon SDE II interview experience from Bangalore covering 4 rounds, DSA, LLD, system design, Leadership Principles, coding questions and selection.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531304Z","viewCount":0},{"id":212,"title":"How to Get 10x Better AI Answers Without Writing Better Prompts : 10 Proven Techniques","url":"how-to-get-10x-better-ai-answers-without-writing-better-prompts-10-proven-techniques","description":null,"seoDescription":"Get better AI answers without complex prompts. Learn 10 practical techniques using context, examples, tools, feedback, and verification.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531316Z","viewCount":0},{"id":211,"title":"I Interviewed for a Microsoft SDE I Role. Here's Everything That Happened.","url":"i-interviewed-for-a-microsoft-sde-i-role-heres-everything-that-happened","description":null,"seoDescription":"My real Microsoft SDE I interview experience, all 4 rounds, the exact DSA problems with fully tested solutions, the WhatsApp system design round","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531329Z","viewCount":0},{"id":140,"title":"PolicyBazaar Software Development Engineer (SDE) Interview Experience | DSA, Core CS & System Design","url":"policybazaar-software-development-engineer-sde-interview-experience-dsa-core-cs-system-design","description":null,"seoDescription":"Detailed PolicyBazaar SDE interview experience covering 3 rounds: DSA coding, core CS assessment and system design with key learnings and insights.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1531342Z","viewCount":0}],"relatedContents":[{"id":105,"title":"Minimum Cost to Sort an Array by Sorting Subarrays","url":"minimum-cost-to-sort-an-array-by-sorting-subarrays","description":null,"seoDescription":"Minimum Cost to Sort Array problem explained with brute force, optimal approach, chunks, DSA intuition, Java/C++/Python/C# solutions.","contentType":5,"generatedOn":"2026-10-07T01:30:25.1750037Z","viewCount":0},{"id":146,"title":"Amazon Transaction Logs","url":"amazon-transaction-logs","description":null,"seoDescription":"Amazon Transaction Logs (example question), Amazon Transaction Logs Interview question","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750055Z","viewCount":0},{"id":9,"title":"Find the Missing Number","url":"find-the-missing-number","description":null,"seoDescription":"Given an integer range of 1 to N in an array arr[] of size N-1. Write a code to find missing number from that array.","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750071Z","viewCount":0},{"id":3,"title":"Remove Duplicates from Sorted Array II","url":"remove-duplicates-from-sorted-array-ii","description":null,"seoDescription":"Given a sorted integer array in ascending order , remove all duplicates from this array so that each unique element appears at most twise in this array. also maintain relative order of the elements in array.","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750086Z","viewCount":0},{"id":2,"title":"Remove Duplicates from Sorted Array","url":"remove-duplicates-from-sorted-array","description":null,"seoDescription":"Given an integer sorted array (arr) in ascending order , remove all duplicates from this array so that each unique element appears only once in this array. also maintain relative order of the elements in array","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750105Z","viewCount":0},{"id":1,"title":"Merge Sorted Array","url":"merge-sorted-array","description":null,"seoDescription":"You are given two integer arrays arr1 and arr2, sorted in accending order, and two integers m and n, representing the number of elements in arr1 and arr2 respectively. Merge arr1 and arr2 into a single array sorted in accending order.","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750122Z","viewCount":0},{"id":138,"title":"Two Sum - Pair with given Sum","url":"two-sum-pair-with-given-sum","description":null,"seoDescription":"Two Sum – Pair with given Sum , 2 sum problem , array DSA problem, coding problem , DSA coding problem , DSA interview coding problem","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750137Z","viewCount":0},{"id":139,"title":"2 Sum Count pairs with given sum","url":"2-sum-count-pairs-with-given-sum","description":null,"seoDescription":"2 Sum – Count pairs with given sum, two sum , Count pairs with given sum , 2 sum problem , array DSA problem, coding problem , DSA interview coding problem","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750156Z","viewCount":0},{"id":141,"title":"2 Sum – Count Pairs with given Sum in Sorted Array","url":"2-sum-count-pairs-with-given-sum-in-sorted-array","description":null,"seoDescription":"2 Sum – Count Pairs with given Sum in Sorted Array, two sum , Count pairs with given sum , 2 sum problem , array DSA problem, coding problem , DSA interview coding problem","contentType":2,"generatedOn":"2026-10-07T01:30:25.1750176Z","viewCount":0}]}}},"source":{"isMobile":false}}; window.__CLIENT_RENDER__ = false;