Program to find number of magic sets from a permutation of first n natural numbers in Python

Suppose we have an array A with first n natural numbers, and one permutation P{p1, p2, ... pn} of array A. We have to check how many magic sets are there. A permutation is said to be magic set, if this satisfies these few rules ?

  • If we have k, then the elements in positions a[1], a[2], ... a[k] are less than their adjacent elements [P[a[i] - 1] > P[a[i]]
  • If we have l, then the elements in positions b[1], b[2], ... b[l] are greater than their adjacent elements [P[b[i] - 1] P[b[i] + 1]]

So, if the input is like n = 4, k = 1, l = 1, k_vals = [2], l_vals = [3], then the output will be 5 because: N = 4, a[1] = 2 and b[1] = 3. So the five permutations are [2,1,4,3], [3,2,4,1], [4,2,3,1], [3,1,4,2], [4,1,3,2].

Algorithm

To solve this, we will follow these steps ?

  • p := 10^9+7
  • F := An array of size n+2 and fill with 0
  • for each a in k_vals, do
    • if F[a - 1] is 1 or F[a + 1] is 1, then
      • return 0 (invalid configuration)
    • F[a] := 1
  • for each b in l_vals, do
    • if F[b] is 1 or F[b - 1] is -1 or F[b + 1] is -1, then
      • return 0 (invalid configuration)
    • F[b] := -1
  • Use dynamic programming to count valid permutations

Implementation

Let us see the following implementation to get better understanding ?

def solve(n, k, l, k_vals, l_vals):
    p = 10**9+7
    F = [0] * (n + 2)
    
    # Mark valley positions (elements less than adjacent)
    for a in k_vals:
        if F[a - 1] == 1 or F[a + 1] == 1:
            return 0  # Invalid configuration
        F[a] = 1
    
    # Mark peak positions (elements greater than adjacent)
    for b in l_vals:
        if F[b] == 1 or F[b - 1] == -1 or F[b + 1] == -1:
            return 0  # Invalid configuration
        F[b] = -1
    
    # Dynamic programming to count valid permutations
    A = [0] * (n + 1)
    B = [0] * (n + 1)
    FF = [None] * (n + 1)
    
    # Calculate differences
    for i in range(1, n + 1):
        FF[i] = F[i] - F[i - 1]
    
    A[1] = 1
    
    # DP iteration
    for i in range(2, n + 1):
        for j in range(1, i + 1):
            if FF[i] > 0:
                B[j] = (B[j - 1] + A[j - 1]) % p
            elif FF[i] < 0:
                B[j] = (B[j - 1] + A[i - 1] - A[j - 1]) % p
            else:
                B[j] = (B[j - 1] + A[i - 1]) % p
        A, B = B, A
    
    return A[n]

# Test the function
n = 4
k = 1
l = 1
k_vals = [2]
l_vals = [3]
result = solve(n, k, l, k_vals, l_vals)
print(f"Number of magic sets: {result}")

Output

Number of magic sets: 5

How It Works

The algorithm uses dynamic programming to count valid permutations:

  • Step 1: Mark valley positions (k_vals) with 1 and peak positions (l_vals) with -1
  • Step 2: Check for conflicts between adjacent positions
  • Step 3: Use DP to count permutations that satisfy all constraints
  • Step 4: The FF array tracks transitions between valley/peak/neutral positions

Conclusion

This algorithm efficiently counts magic permutations by using dynamic programming with constraint validation. The time complexity is O(n²) and it handles edge cases where adjacent positions have conflicting requirements.

Updated on: 2026-03-26T18:15:10+05:30

199 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements