把以前比赛时候没写的题补一补,看看哪个能写。
wannafly挑战赛6D-锁
https://www.nowcoder.com/acm/contest/37/D
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
/* 今天下午把 比赛打完之后,歇一会,把蓝桥杯的也打一打。
其实最重要的是,我觉得是, 把以前那些我写的代码,题解在整整,
因为有的题解我感觉不是那么的好,还可以枸一枸
*/
/*
这道题的意思是
链接:https://www.nowcoder.com/acm/contest/37/D
来源:牛客网
106号房间共有n名居民, 他们每人有一个重要度。
房间的门上可以装若干把锁。假设共有k把锁,命名为1到k。
每把锁有一种对应的钥匙,也用1到k表示。钥匙可以复制并发给任意多个居民
。每个106房间的居民持有若干钥匙,也就是1到k的一个子集。
如果几名居民的钥匙的并集是1到k,即他们拥有全部锁的对应钥匙,
他们都在场时就能打开房门。新的陆战协定规定,
一组居民都在场时能打开房门当且仅当他们的重要度加起来至少为m。
问至少需要给106号房间装多少把锁。即,求最小的k,
使得可以适当地给居民们每人若干钥匙(即一个1到k的子集),
使得任意重要度之和小于m的居民集合持有的钥匙的并集不是1到k,
而任意重要度之和大于等于m的居民集合持有的钥匙的并集是1到k。
*/
/* 这道题我是觉得很苟的一道题。
因为这是一道彻头彻尾的思维题。
思路:
1. 样例6的意思是,当锁为6时,存在一种分配钥匙的方法,使得任意2人加起来,都不能凑齐1-6的钥匙;而任意3人加起来都可以凑出1-6的钥匙;
2. 一共有n个人,需要m重要度,求出至少几把锁k;先定义**临界分组**:重要度不足m,但是加上任何一个其他人,重要度都大于等于m;
3. 使得这样的临界分组中,每个分组钥匙的并集缺1把钥匙,而改组外的人都有缺的这把钥匙;
4. 每个分组中缺的钥匙都不相同(如果相同的话那么可以得到重要度>=m的却开不了门),所以,**临界分组的个数=钥匙的种类=锁的最少数** ;
5. 一共有n个人,所以可以构建出2^n种组,找出其中的临界分组的数目即可。
(这是大佬写的。。)
可是为什么这样写是可以的呢?
我是这样理解的,因为如果一个分组不是临界分组,
1 他分组中元素的 重要度和加上 任意给的人的重要度和仍不能变成临界分组,那么
他加上有限人,总可以达到 临界分组的状态,不需要考虑
2 如果他当前元素重要度和依然大于m,那么他即可以成为临界分组成功的状态。
所以仍可以不需要考虑
是故,我们只需要计算临界分组即可。
*/
using namespace std;
const int maxn=1e3;
#define a_i a[i]
#define a_j a[j]
typedef long long ll;
vector<ll>q;
ll a[maxn];
int main()
{ int n;
ll m;
while(cin>>n>>m){
int num=0;
for(int i=0;i<n;i++){
cin>>a_i;
}
for(int i=0;i<(1<<n);i++){
//枚举集合状态
q.clear();
ll sum=0;
for(int j=0;j<n;j++){
if(i&(1<<j)){
sum+=a_j;
}
else q.push_back(a_j);
}
//处理临界数组
if(sum<m){
bool flag=true;
for(int j=0;j<q.size();j++){
if(sum+q[j]<m){//临界分组是存在任意
flag=false;
}
}
if(flag){
num++;
}
}
}
printf("%d\n",num);
}
return 0;
}