牛客网好题

把以前比赛时候没写的题补一补,看看哪个能写。
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值