贪心+状压
考虑到球队人数很小,状压枚举球队每个位置,\(f_{i,j}\)表示dp到i人,球队组成为j的最大值
由于要使贡献最大,可以先按照\(b_i\)降序,然后每次转移时,若选这个人,加入球队,否则若啦啦队没满,就放进啦啦队
由于没有使用贪心而强行枚举\(b_i\)最大的p+k里的球队人数,导致复杂度多个p而卡了许久
#include<bits/stdc++.h>
using namespace std;
const long long inf=-1e14;
const int N=1e5+11;
struct ab_{
int a[8],b;
}sx[N];
int n,p,k;
long long f[N][128];
inline int read()
{
int s=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
ch=getchar();
}
return s;
}
inline void max_(long long &a,long long b){if(a<b)a=b;return;}
bool cmp1(ab_ a,ab_ b){return a.b>b.b;}
bool cmp2(ab_ a,ab_ b){return a.b<b.b;}
int js(int x){int sum=0;while(x){x-=(x&-x);++sum;}return sum;}
signed main()
{
n=read();
p=read();
k=read();
for(int i=1;i<=n;++i) sx[i].b=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=p;++j)
sx[i].a[j]=read();
sort(sx+1,sx+n+1,cmp1);
long long sum=0;
int M=(1<<p)-1;
for(int i=1;i<=p+k;++i) sum+=sx[i].b;
for(int i=1;i<=p+k;++i) for(int j=1;j<=p;++j) sx[i].a[j]-=sx[i].b;
for(int i=0;i<=n;++i) for(int j=0;j<=M;++j) f[i][j]=inf;
f[0][0]=0;
if(p+k==n)
{
for(int i=1;i<=n;++i)
{
for(int j=0;j<M;++j)
for(int h=1;h<=p;++h)
if(!((1<<h-1)&j))
max_(f[i][j|(1<<h-1)],f[i-1][j]+sx[i].a[h]);
for(int j=0;j<=M;++j) max_(f[i][j],f[i-1][j]);
}
cout<<sum+f[n][M]<<endl;
return 0;
}
long long ans=0;
for(int i=0;i<=p+k;++i) for(int j=0;j<=M;++j) f[i][j]=inf;
f[0][0]=0;
for(int i=1;i<=p+k;++i)
{
for(int j=0;j<M;++j)
for(int h=1;h<=p;++h)
if(!((1<<h-1)&j))
max_(f[i][j|(1<<h-1)],f[i-1][j]+sx[i].a[h]);
for(int j=0;j<=M;++j) max_(f[i][j],f[i-1][j]);
}
ans=f[p+k][M]+sum;
for(int g=1;g<=p;++g)
{
sum-=sx[p+k-g+1].b;
for(int i=1;i<=p;++i) sx[p+k-g+1].a[i]+=sx[p+k-g+1].b;
memset(f,-0x3f,sizeof(f));
f[p+k-g][0]=0;
for(int i=p+k-g+1;i<=n;++i)
{
for(int j=0;j<M;++j)
{
if(js(j)>g) continue;
if(f[i-1][j]<inf) continue;
for(int h=1;h<=p;++h)
if(!((1<<h-1)&j))
max_(f[i][j|(1<<h-1)],f[i-1][j]+sx[i].a[h]);
}
for(int j=0;j<=M;++j) max_(f[i][j],f[i-1][j]);
}
f[0][0]=0;
for(int i=1;i<=p+k-g;++i)
{
for(int j=0;j<M;++j)
{
if(js(j)>p-g) continue;
if(f[i-1][j]<inf) continue;
for(int h=1;h<=p;++h)
if(!((1<<h-1)&j))
max_(f[i][j|(1<<h-1)],f[i-1][j]+sx[i].a[h]);
}
for(int j=0;j<=M;++j) max_(f[i][j],f[i-1][j]);
}
for(int i=0;i<=M;++i)
{
if(js(i)!=g)continue;
max_(ans,f[p+k-g][M-i]+f[n][i]+sum);
}
}
cout<<ans<<endl;
return 0;
}