CF1316E Team Building

贪心+状压

考虑到球队人数很小,状压枚举球队每个位置,\(f_{i,j}\)表示dp到i人,球队组成为j的最大值

由于要使贡献最大,可以先按照\(b_i\)降序,然后每次转移时,若选这个人,加入球队,否则若啦啦队没满,就放进啦啦队

以上是正解,这是laji做法:

由于没有使用贪心而强行枚举\(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;
}

posted @ 2021-11-01 17:49  sitiy  阅读(38)  评论(2编辑  收藏  举报