牛客寒假营-战棋小孩-(状态压缩)

C

题意:
就是给你n次比赛,每次比赛上榜需要的分数,你的初始分数,每次比赛有4个分数可以选择,还有m次魔法,如果在某一场用魔法,那么这场的后两个分数也可以挑。如果不用魔法就只能从前两个分数中挑一个。当然你可以让比赛的顺序随便改变。

思考:
刚开始看了看人过的不多,然后最后看了看,难道是dp吗,但是感觉dp又不能写。最后看了一眼数据我范围,n和m才20,那么很明显了。二进制枚举所有魔法用在哪场比赛。但是这里又卡住我了,从n位中选m位,这咋二进制。以前用的从n位中直接随便选的那种。可能昨天太傻逼了,其实还是直接枚举0到1ll<<n,然后看看如果选i的时候1的位数大于m了就不要,跳过就行了。所以每次比赛都尽可能选最大的,然后从大到小排序贪心一下。
值得注意的呢是,虽然2的20次方挺大的,但是真正能到下面的很少,所以最终是不大的。还有就是对于标记的能用数组vis就用数组,unordered其实还是有点慢,特别是用的次数特别多的时候。

代码:

int T,n,m,k;
int sc[N];
int va[N],vb[N],vc[N],vd[N];
int vis[N];

signed main()
{
	IOS;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++) cin>>sc[i];
	for(int i=1;i<=n;i++) cin>>va[i]>>vb[i]>>vc[i]>>vd[i];
	int ans = 0;
	for(int i=0;i<(1ll<<n);i++)
	{
		int cnt = 0;
		for(int j=1;j<=n;j++) vis[j] = 0;
		for(int j=0;j<n;j++) if(i>>j&1) vis[j+1] = 1,cnt++;
		if(cnt>m) continue;
		vector<int > anw;
		for(int j=1;j<=n;j++)
		{
			int maxn = max(va[j],vb[j]);
			if(vis[j]) maxn = max(maxn,max(vc[j],vd[j]));
			anw.pb(maxn);
		}
		sort(anw.begin(),anw.end(),greater<int>());
		int sum = k,res = 0;
		for(int j=1;j<=n;j++)
		{
			sum += anw[j-1];
			if(sum>=sc[j]) res++;
		}
		ans = max(ans,res);
	}
	cout<<ans;
	return 0;
}

总结:
不要太慌张,一点一点思考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值