Team Building (Codeforces 1316E)
Tags: Greedy, bitmasks

Alice, the president of club FCB, wants to build a team for the new volleyball tournament. The team should consist of $$$p$$$ players playing in $$$p$$$ different positions. She also recognizes the importance of audience support, so she wants to select $$$k$$$ people as part of the audience.There are $$$n$$$ people in Byteland. Alice needs to select exactly $$$p$$$ players, one for each position, and exactly $$$k$$$ members of the audience from this pool of $$$n$$$ people. Her ultimate goal is to maximize the total strength of the club.The $$$i$$$-th of the $$$n$$$ persons has an integer $$$a_{i}$$$ associated with him — the strength he adds to the club if he is selected as a member of the audience.For each person $$$i$$$ and for each position $$$j$$$, Alice knows $$$s_{i, j}$$$  — the strength added by the $$$i$$$-th person to the club if he is selected to play in the $$$j$$$-th position.Each person can be selected at most once as a player or a member of the audience. You have to choose exactly one player for each position.Since Alice is busy, she needs you to help her find the maximum possible strength of the club that can be achieved by an optimal choice of players and the audience.

Input: The first line contains $$$3$$$ integers $$$n,p,k$$$ ($$$2 \leq n \leq 10^{5}, 1 \leq p \leq 7, 1 \le k, p+k \le n$$$).The second line contains $$$n$$$ integers $$$a_{1},a_{2},\ldots,a_{n}$$$. ($$$1 \leq a_{i} \leq 10^{9}$$$).The $$$i$$$-th of the next $$$n$$$ lines contains $$$p$$$ integers $$$s_{i, 1}, s_{i, 2}, \dots, s_{i, p}$$$. ($$$1 \leq s_{i,j} \leq 10^{9}$$$)

Output: Print a single integer $$${res}$$$  — the maximum possible strength of the club.

Note: In the first sample, we can select person $$$1$$$ to play in the $$$1$$$-st position and persons $$$2$$$ and $$$3$$$ as audience members. Then the total strength of the club will be equal to $$$a_{2}+a_{3}+s_{1,1}$$$.

Sample Inputs:
4 1 2
1 16 10 3
18
19
13
15

6 2 3
78 93 9 17 13 78
80 97
30 52
26 17
56 68
60 36
84 55

3 2 1
500 498 564
100002 3
422332 2
232323 1

Sample Outputs:
44

377

422899

Solution (Python):
import io
import os
popcount = []
for mask in range(1 << 7):
    popcount.append(bin(mask).count('1'))
maskToPos = []
for mask in range(1 << 7):
    maskToPos.append([i for i in range(7) if mask & 1 << i])
inf = float('inf')

def solve(N, P, K, audienceScore, playerScore):
    scores = sorted(zip(audienceScore, playerScore), reverse=True)
    scoresA = [0.0 for i in range(N)]
    scoresP = [0.0 for i in range(7 * N)]
    for (i, (a, ps)) in enumerate(scores):
        scoresA[i] = float(a)
        for (j, p) in enumerate(ps):
            scoresP[7 * i + j] = float(p)
    f = [-inf for mask in range(1 << P)]
    nextF = [-inf for mask in range(1 << P)]
    f[0] = scoresA[0]
    for pos in range(P):
        f[1 << pos] = scoresP[pos]
    for n in range(1, N):
        for mask in range(1 << P):
            best = f[mask]
            if n - popcount[mask] < K:
                best += scoresA[n]
            for pos in maskToPos[mask]:
                best = max(best, scoresP[7 * n + pos] + f[mask - (1 << pos)])
            nextF[mask] = best
        (f, nextF) = (nextF, f)
    return int(max(f))
if __name__ == '__main__':
    input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
    (N, P, K) = list(map(int, input().split()))
    audienceScore = [int(x) for x in input().split()]
    playerScore = [[int(x) for x in input().split()] for i in range(N)]
    ans = solve(N, P, K, audienceScore, playerScore)
    print(ans)

Solution (Python):
import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = 'x' in file.mode or 'r' not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b'\n') + (not b)
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            (self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode('ascii'))
        self.read = lambda : self.buffer.read().decode('ascii')
        self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
inf = float('inf')
(n, p, k) = map(int, input().split())
a = list(map(int, input().split()))
s = [None for _ in range(n)]
I = list(range(n))
I.sort(key=lambda i: -a[i])
ref = {x: i for (i, x) in enumerate(I)}
a.sort(reverse=True)
for i in range(n):
    s[ref[i]] = list(map(int, input().split()))
dp = [-inf] * (1 << p)
dp[0] = float(a[0])
for j in range(p):
    dp[1 << j] = float(s[0][j])
Bit_cnt = [bin(mask).count('1') for mask in range(1 << p)]
for i in range(1, n):
    new_dp = [-inf] * (1 << p)
    for mask in range(1 << p):
        bit_cnt = Bit_cnt[mask]
        if i + 1 - bit_cnt <= k:
            new_dp[mask] = dp[mask] + a[i]
        else:
            new_dp[mask] = dp[mask]
        for j in range(p):
            if not mask & 1 << j:
                continue
            case = dp[mask ^ 1 << j] + s[i][j]
            new_dp[mask] = max(new_dp[mask], case)
    dp = new_dp
print(int(dp[(1 << p) - 1]))

Solution (Python):
import io
import os
from array import array
DEBUG = False
if DEBUG:
    from functools import lru_cache

    def solveTopDown(N, P, K, audienceScore, playerScore):
        assert len(audienceScore) == len(playerScore) == N
        scores = sorted(zip(audienceScore, playerScore), reverse=True)
        audienceScore = [a for (a, p) in scores]
        playerScore = [p for (a, p) in scores]

        @lru_cache(maxsize=None)
        def f(n, mask):
            if n == 0:
                if mask == 0:
                    return audienceScore[n]
                else:
                    for pos in range(P):
                        if mask == 1 << pos:
                            return playerScore[n][pos]
                    return float('-inf')
            best = f(n - 1, mask)
            num = n + 1
            numPlayers = _popcount[mask]
            if num - numPlayers <= K:
                best += audienceScore[n]
            for pos in range(P):
                if 1 << pos & mask:
                    best = max(best, playerScore[n][pos] + f(n - 1, mask - (1 << pos)))
            return best
        best = 0
        for i in range(N):
            for mask in range(1 << P):
                val = f(i, mask)
                best = max(best, val)
        return best

def popcount(i):
    assert 0 <= i < 4294967296
    i = i - (i >> 1 & 1431655765)
    i = (i & 858993459) + (i >> 2 & 858993459)
    return ((i + (i >> 4) & 252645135) * 16843009 & 4294967295) >> 24
_popcount = []
for mask in range(1 << 7):
    _popcount.append(popcount(mask))
maskToPos = []
for mask in range(1 << 7):
    maskToPos.append([i for i in range(7) if mask & 1 << i])
negInf = float('-inf')

def solve(N, P, K, audienceScore, playerScore):
    scores = sorted(zip(audienceScore, playerScore), reverse=True)
    scoresA = [0.0 for i in range(N)]
    scoresP = [0.0 for i in range(7 * N)]
    for (i, (a, ps)) in enumerate(scores):
        scoresA[i] = float(a)
        for (j, p) in enumerate(ps):
            scoresP[7 * i + j] = float(p)
    f = [negInf for mask in range(1 << P)]
    nextF = [negInf for mask in range(1 << P)]
    f[0] = scoresA[0]
    for pos in range(P):
        f[1 << pos] = scoresP[pos]
    for n in range(1, N):
        for mask in range(1 << P):
            best = f[mask]
            if n - _popcount[mask] < K:
                best += scoresA[n]
            for pos in maskToPos[mask]:
                best = max(best, scoresP[7 * n + pos] + f[mask - (1 << pos)])
            nextF[mask] = best
        (f, nextF) = (nextF, f)
    return int(max(f))
if DEBUG:
    from random import randint
    N = 100000
    P = 7
    K = 90000
    audienceScore = [randint(1, 100) for i in range(N)]
    playerScore = [[randint(1, 100) for j in range(7)] for i in range(N)]
    ans = solve(N, P, K, audienceScore, playerScore)
    if False:
        assert ans == solveTopDown(N, P, K, audienceScore, playerScore)
    exit()
if __name__ == '__main__':
    input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
    (N, P, K) = list(map(int, input().split()))
    audienceScore = [int(x) for x in input().split()]
    playerScore = [[int(x) for x in input().split()] for i in range(N)]
    ans = solve(N, P, K, audienceScore, playerScore)
    print(ans)