CodeCraft-20 (Div. 2)E. Team Building

20 篇文章 0 订阅
18 篇文章 0 订阅

E. team Building

Face


题意

  • n n n个人里选 p p p人参加比赛, 选 k k k人当观众 ( n ≥ p + k ) (n\geq p+k) (np+k)
  • i i i人当观众可以给答案带来贡献 a i a_i ai
  • i i i人第 j j j个参赛可以给答案带来贡献 m a t [ i ] [ j ] mat[i][j] mat[i][j]
  • 现给定如上数据, 求贡献最大

数据范围: 2 ≤ n ≤ 1 0 5 , 1 ≤ q ≤ 7 , 1 ≤ k , k + p ≤ n 2\leq n\leq 10^5, 1\leq q \leq 7, 1\leq k, k + p\leq n 2n105,1q7,1k,k+pn


前置技能
  • 状压 d p dp dp
Tutorial:
  • 要是没有k的限制就是个裸的状压, 先贪心的考虑 a [ i ] a[i] a[i]最大的前 k + q k+q k+q个, 其中每个元素有三个选择, 要么当运动员, 要么当观众, 要么啥都不干, 可以看出来, 如果 a [ i ] < a [ j ] a[i] < a[j] a[i]<a[j], 那么无论如何, a[j]都不可能啥都不干, 所以我们可以对 a [ i ] a[i] a[i]排个序, 然后状压转移, 由于k的限制, 当观众人数超过k的时候, 就不能贡献了, 所以转移方程肯定是由当前人数决定的
  • 如何求目前观众的人数呢, i - mask(bits), 目前考虑到的人减去目前当运动员的人, 那么状态方程就很好想了:
    { d p [ i ] [ n e w ] = m a x ( d p [ i ] [ n e w ] , d p [ i − 1 ] [ o l d ] + m a t [ x ] [ e + 1 ] ) d p [ i ] [ c u r ] = m a x ( d p [ i − 1 ] [ c u r ] + a [ x ] , d p [ i ] [ c u r ] ) 第 i 人 可 以 当 观 众 d p [ i ] [ c u r ] = m a x ( d p [ i ] [ c u r ] , d p [ i − 1 ] [ c u r ] ) ; 第 i 人 不 能 当 观 众 \begin{dcases} dp[i][new] = max(dp[i][new], dp[i-1][old] + mat[x][e + 1]) \\ dp[i][cur] = max(dp[i - 1][cur] + a[x], dp[i][cur]) 第i人可以当观众\\ dp[i][cur] = max(dp[i][cur], dp[i - 1][cur]); 第i人不能当观众 \end{dcases} dp[i][new]=max(dp[i][new],dp[i1][old]+mat[x][e+1])dp[i][cur]=max(dp[i1][cur]+a[x],dp[i][cur])idp[i][cur]=max(dp[i][cur],dp[i1][cur]);i
具体步骤:
  • s o r t sort sort使得 a a a降序
  • 构造状态 d p [ i ] [ m a s k ] dp[i][mask] dp[i][mask]表示从 1 , 2 , 3 , ⋯ i 1, 2, 3 , \dotsm i 1,2,3,i里选择状态为 m a s k mask mask的最大收益
  • 转移状态
复杂度: O ( n × 2 p + n l o g ( n ) ) O(n\times 2^p + nlog(n)) O(n×2p+nlog(n))

code:



#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3fll
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<ll, ll>
#define pdd pair<db, db>
#define pi acos(-1.0)
#define lowbit(x) x&(-x)
const ll maxn = 1e5 + 10;
const ll mod = 1e9;
ll dp[maxn][1 << 8];
int n, p, k;
ll a[maxn], id[maxn];


ll mat[maxn][8];
signed main()
{
	cin >> n >> p >> k;
	_rep(i, 1, n) cin >> a[i];
	_rep(i, 1, n) id[i] = i;
	sort(id + 1, id + 1 + n, [](ll& x, ll& y) { return a[x] > a[y]; });
	_rep(i, 1, n)
	{
		_rep(j, 1, p)
		{
			cin >> mat[i][j];
		}
	}

	_rep(i, 1, n)
	{
		ll x = id[i];
		_rep(cur, 0, (1 << p) - 1)
		{
			ll has = __builtin_popcount(cur);

			has = i - has;
			if (has <= 0)continue;
			if (has <= k) //第x人要么是观众要么选他
			{
				dp[i][cur] = max(dp[i - 1][cur] + a[x], dp[i][cur]);
				_for(e, 0, p)
				{
					if (!((cur >> e) & 1)) //第i位是0
					{
						dp[i][cur ^ (1 << e)] = max(dp[i][cur ^ (1 << e)], dp[i - 1][cur] + mat[x][e + 1]);
					}
				}
			}
			else
			{
				dp[i][cur] = max(dp[i][cur], dp[i - 1][cur]);
				_for(e, 0, p)
				{
					if (!((cur >> e) & 1)) //第i位是0
					{
						dp[i][cur ^ (1 << e)] = max(dp[i][cur ^ (1 << e)], dp[i - 1][cur] + mat[x][e + 1]);
					}
				}
			}
		}
	}
	cout << dp[n][(1 << p) - 1] << endl;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值