题目传送门
题目大意:
个人,从中选择
个作为球员,第
个人产生
,
个作为观众,第
个人产生
的价值
解题思路
不难想,通过对用二进制进行状态压缩,到一个简单的
过程
这种做法的复杂度大约是显然是不可接受的
然后不难发现作为观众的人,其实只要贪心的在没有选为球员的人里面选最大的个就好了
于是又得以去掉的复杂度,于是就可以接受了
设为前
个人中选择状态为
的最大价值,所有人先按
降序排序
如果时,直接将
加入答案,其中
表示
在二进制表示下
的个数。
因为此时剩余可选人数不足人,显然所有剩余的
都是最优的。否则在这种状态下肯定已经选择了
个最优的
,不用再选择了
之后枚举,将第
个人放在第
个位置,当
时
因为状态从
转移过来,不用担心前一步选择
的影响,保证了无后效性
AC代码
//#pragma GCC optimize(3,"Ofast","inline") #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #include <map> #include <set> #include <stack> #include <vector> #include <string> #include <iostream> #include <list> #include <cstdlib> #include <bitset> #include <assert.h> #include <iomanip> // #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) // char buf[(1 << 21) + 1], * p1 = buf, * p2 = buf; // #define int long long #define lowbit(x) (x & (-x)) #define lson root << 1, l, mid #define rson root << 1 | 1, mid + 1, r #define pb push_back typedef unsigned long long ull; typedef long long ll; typedef std::pair<int, int> pii; typedef std::pair<ll, ll> pll; #define bug puts("BUG") const long long INF = 0x3f3f3f3f3f3f3f3fLL; const int inf = 0x3f3f3f3f; const int mod = 97654321; const double eps = 1e-6; template <class T> inline void read(T &x) { int sign = 1;char c = getchar();x = 0; while (c > '9' || c < '0'){if (c == '-')sign = -1;c = getchar();} while (c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();} x *= sign; } #ifdef LOCAL FILE* _INPUT=freopen("input.txt", "r", stdin); // FILE* _OUTPUT=freopen("output.txt", "w", stdout); #endif using namespace std; const int maxn = 1e5 + 10; int s[maxn][7], sz[1 << 7]; int a[maxn], pos[maxn]; bool cmp(int i, int j) { return a[i] > a[j]; } ll dp[2][1 << 7]; int main() { int n, p, k; read(n), read(p), read(k); for (int i = 1; i <= n; ++i) { read(a[i]); pos[i] = i; } for (int i = 1; i <= n; ++i) { for (int j = 0; j < p; ++j) { read(s[i][j]); } } for (int i = 0; i < (1 << p); ++i) { sz[i] = sz[i >> 1] + (i & 1); } sort(pos + 1, pos + 1 + n, cmp); int now = 0, pre = 1; memset(dp, 0x80, sizeof dp);//0x80808080 < 0 dp[now][0] = 0; for (int v = 1; v <= n; ++v) { int i = pos[v]; swap(now, pre); memset(dp[now], 0x80, sizeof dp[now]); for (int j = 0; j < (1 << p); ++j) { if (dp[pre][j] < 0) continue; if (v - sz[j] <= k) dp[now][j] = max(dp[now][j], dp[pre][j] + a[i]); else dp[now][j] = max(dp[now][j], dp[pre][j]); for (int l = 0; l < p; ++l) if ((j | (1 << l)) != j) { dp[now][j | (1 << l)] = max(dp[now][j | (1 << l)], dp[pre][j] + s[i][l]); } } } printf("%lld\n", dp[now][(1 << p) - 1]); }