(CF1316E Team Building)
Solution
我们先考虑一个简单的暴力。
我们设 (f_{i,j,T}) 表示前 (i) 个人,选择了其中 (j) 个作为观众,队伍中的人选择情况(状压)。
转移比较显然:
[f_{i,j,T}=max (f_{i-1,j,T},f_{i-1,j-1,T}+a_i)\\
f_{i,j,T}=max_{k=1}^p(f_{i-1,j,T Xor 2^{k-1}}+s_{i,k})
]
时间复杂度是 (O(2^nnkp)) 。
但是,我们发现,当确定了哪些人进入排球队时,观众一定是选 (a_i) 最大的 (k) 个。
我们将所有人按 (a_i) 从大到小排序。
设 (f_{i,T}) 表示前 (i) 个人,队伍哪些人确定。
那么显然,我们已经确定作为观众的人数是 (min(k,i-1-popcnt(T))) 。
那么转移就是:
[f_{i,T}=f_{i-1,T}\\
f_{i,T}=f_{i-1,T}+a_i ,i-popcnt(T)leq k\\
f_{i,T}=max_{j=1}^m (f_{i-1,j,T Xor 2^{j-1}}+s_{i,j})
]
Code
#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
int f=1;char k=getchar();x=0;
for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
for(;k>='0'&&k<='9';k=getchar()) x=x*10+k-'0';
x*=f;
}
template<class T>il _print(T x){
if(x>=10) _print(x/10);
putchar(x%10+'0');
}
template<class T>il print(T x){
if(x<0) putchar('-'),x=-x;
_print(x);
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int k,int mod){
int res=1,bas=x;
while(k){
if(k&1) res=1ll*res*bas%mod;
bas=1ll*bas*bas%mod,k>>=1;
}
return res;
}
const int N = 1e5+5;
int n,m,k,cnt[1<<7];
struct Node{
int val,cost[8];
bool operator < (const Node &t) const {
return val>t.val;
}
}node[N];
ll f[N][1<<7];
il chk_max(ll &x,ll y){x=x>=y?x:y;}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m),read(k);
for(ri i=1;i<=n;++i) read(node[i].val);
for(ri i=1;i<=n;++i) for(ri j=1;j<=m;++j) read(node[i].cost[j]);
sort(node+1,node+1+n);
del(f,-0x3f),f[0][0]=0;
int S=1<<m;
for(ri T=0;T<S;++T) for(ri i=1;i<=m;++i) cnt[T]+=(T&(1<<(i-1)))?1:0;
for(ri i=1;i<=n;++i)
for(ri T=0;T<S;++T){
f[i][T]=f[i-1][T];
if(cnt[T]>i) continue;
if(i-cnt[T]<=k) chk_max(f[i][T],f[i-1][T]+node[i].val);
if(T){
for(ri j=1;j<=m;++j) if(T&(1<<(j-1)))
chk_max(f[i][T],f[i-1][T^(1<<(j-1))]+node[i].cost[j]);
}
}
print(f[n][S-1]);
return 0;
}