P1441 砝码称重

题目传送门

一,题目大意

       现有 n 个砝码,重量分别为 a[ i ]在去掉 m 个砝码后,问最多能称量出多少不同的重量(不包括 0)。

请注意,砝码只能放在其中一边。(指不能使用减法)

二、思路

1、算法

       本题推荐使用状态压缩(不代表其他不行),因为砝码取或者不取的情况较多,所以我们可以用一个二进制序列来表示砝码的使用情况。

       例如 :一个长度为 4 的序列,我们可以用 1001 来表示第一个没有了,第二,三个还留着,第四个也没有了。那么,本来一个很长的序列就可以转换成一个数字了——1001 = 9 。

2、定义

      我们将 1 设为拿走了,0 设为没拿走。之后枚举所有的状态,如果正好拿走的个数为 n − m, 我们再去判断答案,也就是把没拿走的去枚举状态。之后判断每一个是否为 1 。

3、科技(好用的东西)

可以使用bitset 进行二进制计算。bitset 的速度比正常数组快 64 倍。

(1)定义:

bitset可以说是一个多位二进制数,每八位占用一个字节,因为支持基本的位运算,所以可用于状态压缩,n位bitset执行一次位运算的时间复杂度可视为n/32.

(2)一些常见的函数:

s.set()把s所有位变为1;
s.set(k,v)把s的第k位改为v,即s[k]=v;
s.reset()把s的所有位变为0.
s.reset(k)把s的第k位改为0,即s[k]=0;
s.flip()把s所有位取反.即s=~s;
s.flip(k)把s的第k位取反,即s[k]^=1;

若s所有位都为0,则s.any()返回false,s.none()返回true;
若s至少有一位为1,则s.any()返回true,s.none()返回false;

s.count() 返回二进制串中有多少个1   (实测好用)

s[k] :表示s的第k位,即可取值也可赋值,编号从0开始;

三、代(Damn)码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,ans,a[50005],w[50000005];
bitset<2010> s;
int lowbit(int x){
	return (x&-x);
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=(1<<n);i++){
		w[i]=w[i-lowbit(i)]+1;//计算有多少个 1(选了多少数)
		if(w[i] == n - m) {
			s.reset();  //清空
			s[0] = 1;  //初始化,注意 0 不能算作砝码拼出来的
			for(int j = 1; j <= n; j ++){
				if(i & (1 << (j - 1))) { //第 j 个砝码被选了
					s |= s << a[j];
				}
			}
			ans = max(ans, (int)s.count() - 1);
		}
	}
	cout<<ans;
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值