Description
有一支球队 (p) 个人,还可以有 (k) 个人当啦啦队。
给出 (n) 个人在场上每个位置时对球队战斗力的贡献,和当他做啦啦队时的贡献
求出最大球队战斗力
(n le 10^5) , (p le 7)
Solution
这个题首先我们看到场上位置很少,自然想到可以用一个状态压缩过的数字表示球队该状态是的最大收益
转移的时候考虑把当前的人当做啦啦队还是球队里的人
(可能状压不是很好写,我觉得代码挺难理解的)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=1e5+10;
struct node{int id,a;}t[N];
inline bool cmp(node x,node y){return x.a>y.a;}
int f[1010],s[N][9],sz[N],n,p,k;
signed main()
{
n=read(); p=read(); k=read();
for(int i=1;i<=n;++i)
{
t[i].a=read(),t[i].id=i;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=p;++j)
{
s[i][j]=read();
}
}
for(int i=1;i<=1000;++i) sz[i]=sz[i>>1]+(i&1);//预处理每个位上面有几个1
sort(t+1,t+n+1,cmp); memset(f,-0x3f,sizeof(f)); f[0]=0;
int num=(1<<p)-1;
for(int i=1;i<=n;++i)
{
int x=t[i].id;
if(i<=k)
{
for(int j=num;j>=0;--j) f[j]+=t[i].a;
}//如果还没有那么多人,先把这个人扔到啦啦队里面
for(int j=1;j<=p;++j)
{
int ts=num^(1<<(j-1)),l=s[x][j]; //ts指队里面除了这个位置全都有的情况
if(i<=k) l-=t[i].a-t[k+1].a;
f[1<<(j-1)]=max(f[1<<(j-1)],f[0]+l);//只有一个人在队伍里的情况
for(int m=ts;m;m=(m-1)&ts)
{
l=s[x][j];
if(i<=k+sz[m])
{
l-=t[i].a-t[k+sz[m]+1].a;
}
f[m|(1<<(j-1))]=max(f[m|(1<<(j-1))],f[m]+l);
}
}
} printf("%lld
",f[num]);
return 0;
}
}
signed main(){return yspm::main();}