题目链接:
https://codeforces.com/contest/1316/problem/E
题意:
有$n$个人,每个人可以作为运动员和观众,相应位置会有一个权值
只能选择$p$个运动员和$k$个观众,求最大权值
分析:
定义$dp[i][j]$为考虑前$i$个人,运动员选择情况为$j$的最优解
按照作为观众的权值从大到小排序,这样$dp[i-1][j]$的运动员都是在$1$到$i-1$中选择的,保证了转移的可行性
否则,同样$dp[i-1][j]$,有可能选择的是作为观众权值较小的人,这样的最大值不一定就是真正的最优解
转移时考虑当前位置是否已经被选择为观众,如果已经选择为观众,那么减去作为观众的权值即可
AC代码:
#include <bits/stdc++.h> using namespace std; #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,a,b) for (int i=b;i>=a;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef long long ll; typedef vector<int> VI; typedef pair<int,int> PII; const ll mod=1e6+7; const int maxn=1e5+7; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} PII a[maxn]; ll dp[maxn][(1<<7)+7]; int n,p,k,b[maxn][8]; int cal(int x){ int res=0; while(x){ if(x&1)res++; x/=2; } return res; } int main(){ scanf("%d %d %d",&n,&p,&k); rep(i,1,n){ scanf("%d",&a[i].fi); a[i].fi=-a[i].fi; a[i].se=i; } sort(a+1,a+1+n); rep(i,1,n)a[i].fi*=-1; rep(i,1,n)rep(j,1,p)scanf("%d",&b[i][j]); rep(i,1,k)dp[0][0]+=a[i].fi; rep(i,1,n)dp[i][0]=dp[0][0]; rep(i,1,n){ rep(j,1,(1<<p)-1){ dp[i][j]=dp[i-1][j]; int cnt=cal(j); rep(l,0,p-1){ if(j&(1<<l)){ if(cnt-1+k>=i) dp[i][j]=max(dp[i][j],dp[i-1][j-(1<<l)]+b[a[i].se][l+1]-a[i].fi+a[cnt+k].fi); else dp[i][j]=max(dp[i][j],dp[i-1][j-(1<<l)]+b[a[i].se][l+1]); } } } } printf("%lld ",dp[n][(1<<p)-1]); return 0; }