Walk the Runway (Codeforces 1826E)
Tags: Implement, bitmasks

A fashion tour consists of $$$m$$$ identical runway shows in different cities. There are $$$n$$$ models willing to participate in the tour, numbered from $$$1$$$ to $$$n$$$. People in different cities have different views on the fashion industry, so they rate each model differently. In particular, people in city $$$i$$$ rate model $$$j$$$ with rating $$$r_{i, j}$$$.You are to choose some number of $$$k$$$ models, and their order, let the chosen models have indices $$$j_1, j_2, \dots, j_k$$$ in the chosen order. In each city, these $$$k$$$ models will walk the runway one after another in this order. To make the show exciting, in each city, the ratings of models should be strictly increasing in the order of their performance. More formally, for any city $$$i$$$ and index $$$t$$$ ($$$2 \leq t \leq k$$$), the ratings must satisfy $$$r_{i,j_{t - 1}} < r_{i,j_t}$$$. After all, the fashion industry is all about money, so choosing model $$$j$$$ to participate in the tour profits you $$$p_j$$$ money. Compute the maximum total profit you can make by choosing the models and their order while satisfying all the requirements.

Input: The first line contains two integers $$$m$$$ and $$$n$$$ ($$$1 \leq m \leq 500$$$, $$$1 \leq n \leq 5000$$$) — the number of shows and the number of models willing to participate respectively.The second line contains $$$n$$$ integers $$$p_j$$$ ($$$1 \leq p_j \leq 10^9$$$) — the profit you get inviting the $$$j$$$-th model to the tour.The next $$$m$$$ lines each contain $$$n$$$ integers. Line number $$$i$$$ contains $$$n$$$ integers $$$r_{i, j}$$$ ($$$1 \leq r_{i, j} \leq n$$$) — the ratings of models in city $$$i$$$.

Output: Output a single integer — the largest total amount of money you can get.

Note: In the first example, there are $$$3$$$ invited models. The show consists of models in the order $$$[1, 3, 4]$$$.Then, the corresponding ratings in the cities are as follows:   City $$$1$$$ — $$$[ 1, 3, 4 ]$$$.  City $$$2$$$ — $$$[ 1, 2, 3 ]$$$.  City $$$3$$$ — $$$[ 2, 4, 5 ]$$$. You can see that the ratings are increasing. So the total profit is $$$10 + 10 + 10 = 30$$$. It can be proven that we can't achieve a bigger profit.In the second example, we can invite the fifth model to the tour, which would result in a total profit of $$$50$$$. It can be proven that we can't achieve a bigger profit.In the third example, we invite the single model to the tour, which results in a total profit of $$$1\,000\,000\,000$$$.In the fourth test case, we can invite all the models and make the show in the order $$$[ 5, 4, 3, 2, 1 ]$$$. The total profit is $$$5 \cdot 1\,000\,000\,000 = 5\,000\,000\,000$$$.

Sample Inputs:
3 5
10 10 10 10 10
1 2 3 4 5
1 5 2 3 4
2 3 4 5 1

3 5
10 10 10 10 50
1 2 3 4 5
1 5 2 3 4
2 3 4 5 1

1 1
1000000000
1

5 5
1000000000 1000000000 1000000000 1000000000 1000000000
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1

1 3
1 2 3
3 3 3

Sample Outputs:
30

50

1000000000

5000000000

3

Solution (Python):
import sys, os, io
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

def make_graph(n, m):
    (x, s) = ([0] * (2 * m), [0] * (n + 3))
    for i in range(0, 2 * m, 2):
        (u, v) = (r[i >> 1], i >> 1)
        s[u + 2] += 1
        (x[i], x[i + 1]) = (u, v)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    G = [0] * m
    for i in range(0, 2 * m, 2):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        s[j] += 1
    return (G, s)
(m, n) = map(int, input().split())
p = list(map(int, input().split()))
u = 63
pow2 = [1]
for _ in range(u - 1):
    pow2.append(2 * pow2[-1])
z = sum(pow2)
l = n // u + min(n % u, 1)
x = [z] * (l * n)
for _ in range(m):
    r = list(map(int, input().split()))
    (y, s) = make_graph(n, n)
    b = [z] * l
    for i in range(1, n + 1):
        for j in range(s[i], s[i + 1]):
            b[y[j] // u] ^= pow2[y[j] % u]
        for v in range(s[i], s[i + 1]):
            j = y[v] * l
            for k in range(l):
                x[j + k] &= b[k]
dp = [0] * n
for i in y:
    dp0 = dp[i] + p[i]
    j = i * l
    for k in range(n):
        if x[j + k // u] & pow2[k % u]:
            dp[k] = max(dp[k], dp0)
    dp[i] += p[i]
ans = max(dp)
print(ans)

Solution (Python):
import sys, os, io
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

def make_graph(n, m):
    (x, s) = ([0] * (2 * m), [0] * (n + 3))
    for i in range(0, 2 * m, 2):
        (u, v) = (r[i >> 1], i >> 1)
        s[u + 2] += 1
        (x[i], x[i + 1]) = (u, v)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    G = [0] * m
    for i in range(0, 2 * m, 2):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        s[j] += 1
    return (G, s)
(m, n) = map(int, input().split())
p = list(map(int, input().split()))
u = 63
pow2 = [1]
for _ in range(u - 1):
    pow2.append(2 * pow2[-1])
z = sum(pow2)
l = n // u + min(n % u, 1)
x = [z] * (l * n)
for _ in range(m):
    r = list(map(int, input().split()))
    (y, s) = make_graph(n, n)
    b = [z] * l
    for i in range(1, n + 1):
        for j in range(s[i], s[i + 1]):
            b[y[j] // u] ^= pow2[y[j] % u]
        for v in range(s[i], s[i + 1]):
            j = y[v] * l
            for k in range(l):
                x[j + k] &= b[k]
dp = [0] * n
for i in y:
    dp0 = dp[i] + p[i]
    j = i * l
    for k in range(n):
        if x[j + k // u] & pow2[k % u]:
            dp[k] = max(dp[k], dp0)
    dp[i] += p[i]
ans = max(dp)
print(ans)

Solution (Python):
import sys
input = sys.stdin.readline
(m, n) = list(map(int, input().split()))
p = list(map(int, input().split()))
u = 63
pow2 = [1]
for _ in range(u - 1):
    pow2.append(2 * pow2[-1])
z = sum(pow2)
l = n // u + min(n % u, 1)
x = [z] * (l * n)

def make_graph(n, m):
    (x, s) = ([0] * (2 * m), [0] * (n + 3))
    for i in range(0, 2 * m, 2):
        (u, v) = (r[i >> 1], i >> 1)
        s[u + 2] += 1
        (x[i], x[i + 1]) = (u, v)
    for i in range(3, n + 3):
        s[i] += s[i - 1]
    G = [0] * m
    for i in range(0, 2 * m, 2):
        j = x[i] + 1
        G[s[j]] = x[i ^ 1]
        s[j] += 1
    return (G, s)
for _ in range(m):
    r = list(map(int, input().split()))
    (y, s) = make_graph(n, n)
    b = [z] * l
    for i in range(1, n + 1):
        for j in range(s[i], s[i + 1]):
            b[y[j] // u] ^= pow2[y[j] % u]
        for v in range(s[i], s[i + 1]):
            j = y[v] * l
            for k in range(l):
                x[j + k] &= b[k]
dp = [0] * n
for i in y:
    dp0 = dp[i] + p[i]
    j = i * l
    for k in range(n):
        if x[j + k // u] & pow2[k % u]:
            dp[k] = max(dp[k], dp0)
    dp[i] += p[i]
ans = max(dp)
print(ans)