[CodeCraft-20 (Div. 2)]- E. Team Building (状压DP)

E. Team Building

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Alice, the president of club FCB, wants to build a team for the new volleyball tournament. The team should consist of pp players playing in pp different positions. She also recognizes the importance of audience support, so she wants to select kk people as part of the audience.

There are nn people in Byteland. Alice needs to select exactly pp players, one for each position, and exactly kk members of the audience from this pool of nn people. Her ultimate goal is to maximize the total strength of the club.

The ii-th of the nn persons has an integer aiai associated with him — the strength he adds to the club if he is selected as a member of the audience.

For each person ii and for each position jj, Alice knows si,jsi,j — the strength added by the ii-th person to the club if he is selected to play in the jj-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 33 integers n,p,kn,p,k (2≤n≤105,1≤p≤7,1≤k,p+k≤n2≤n≤105,1≤p≤7,1≤k,p+k≤n).

The second line contains nn integers a1,a2,…,ana1,a2,…,an. (1≤ai≤1091≤ai≤109).

The ii-th of the next nn lines contains pp integers si,1,si,2,…,si,psi,1,si,2,…,si,p. (1≤si,j≤1091≤si,j≤109)

Output

Print a single integer resres — the maximum possible strength of the club.

Examples

input

Copy

4 1 2
1 16 10 3
18
19
13
15

output

Copy

44

input

Copy

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

output

Copy

377

input

Copy

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

output

Copy

422899

Note

In the first sample, we can select person 11 to play in the 11-st position and persons 22 and 33 as audience members. Then the total strength of the club will be equal to a2+a3+s1,1a2+a3+s1,1.

题意:

给定n个人员,现在要从其中选择p个球员,k个观众。其中球员又有p个不同的位置,每一个位置最多安排一个人,每一个人最多作为球员或观众中的一个。

第i个人如果被选择作为球员的话,放在第j个位置有\(s_{i,j}\)的价值,如果被选择为观众的话有\(a_i\)的价值。

问你如果采取最优的安排,最大值的价值和为多少?

思路:

首先将\(\mathit a\) 按照非升序排序,

然后定义动态规划的状态\(dp[i][mask]\)\(mask\)\([0,2^p-1]\)范围内的整数,其二进制信息中第\(\mathit j\)位为1,代表球员中的第\(\mathit j\)(下标从0开始算)个位置放了球员。

那么状态\(dp[i][mask]\)代表处理到第\(\mathit i\)个人员,球员安排信息为\(mask\)时的最大价值和。

观众价值处理的转移:

如果\(i,mask\)中还未安放满\(\mathit k\)个观众则有:

\(dp[i+1][mask]=dp[i][mask]+a[i]\)

否则:

\(dp[i+1][mask]=dp[i][mask]\)

球员价值处理的转移:

如果第\(\mathit i\)个人员放在第\(\mathit j\)个位置当球员,则有:\(dp[i][mask] = dp[i-1][mask \oplus 2^j] + s_{i,j}\)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
ll dp[maxn][(1 << 7)];
int n, k, p;
int a[maxn];
int index[maxn];
int s[maxn][7];
bool cmp(int x, int y)
{
    return a[x] > a[y];
}
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    n = readint();
    p = readint();
    k = readint();
    repd(i, 1, n)
    {
        a[i] = readint();
    }
    repd(i, 1, n)
    {
        repd(j, 0, p - 1)
        {
            s[i][j] = readint();
        }
    }
    memset(dp, -1, sizeof(dp));
    dp[0][0] = 0;
    repd(i, 1, n)
    {
        index[i] = i;
    }
    sort(index + 1, index + 1 + n, cmp);
    repd(i, 1, n)
    {
        int maxstate = (1 << p) - 1;
        repd(info, 0, maxstate)
        {
            int num = 0;
            repd(j, 0, p - 1)
            {
                if (info & (1 << j))
                {
                    num++;
                }
            }
            if ((i - 1 - num) < k)
            {
                if (dp[i - 1][info] != -1)
                {
                    dp[i][info] = dp[i - 1][info] + a[index[i]];
                }
            } else
            {
                if (dp[i - 1][info] != -1)
                {
                    dp[i][info] = dp[i - 1][info];
                }
            }
            repd(j, 0, p - 1)
            {
                if (info & (1 << j) && dp[i - 1][info ^ (1 << j)] != -1)
                {
                    dp[i][info] = max(dp[i][info], dp[i - 1][info ^ (1 << j)] + s[index[i]][j]);
                }
            }
        }
    }
    printf("%lld\n", dp[n][(1 << p) - 1] );
    // cout << dp[n][(1 << p) - 1] << endl;
    return 0;
}