锁
题号:NC14732
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
106号房间共有n名居民, 他们每人有一个重要度。房间的门上可以装若干把锁。假设共有k把锁,命名为1到k。每把锁有一种对应的钥匙,也用1到k表示。钥匙可以复制并发给任意多个居民。每个106房间的居民持有若干钥匙,也就是1到k的一个子集。如果几名居民的钥匙的并集是1到k,即他们拥有全部锁的对应钥匙,他们都在场时就能打开房门。新的陆战协定规定,一组居民都在场时能打开房门当且仅当他们的重要度加起来至少为m。问至少需要给106号房间装多少把锁。即,求最小的k,使得可以适当地给居民们每人若干钥匙(即一个1到k的子集),使得任意重要度之和小于m的居民集合持有的钥匙的并集不是1到k,而任意重要度之和大于等于m的居民集合持有的钥匙的并集是1到k。
输入描述:
第一行两个整数n和m,0<n<21,0<m<1000000001。 第二行n个整数表示居民们的重要度。 重要度在[1,1000000000]之间。
输出描述:
一个整数表示最少需要多少把锁。
示例1
输入
4 3 1 1 1 1
输出
6
说明
106号房共有4名居民,只有3人在场时才能打开门。这时共需6把锁。
这道题其实重要的是思想吧!
题意就是当没有最后一个人的时候不满足m
填上最后一个人就满足了!
那么我们可以拿状压来枚举所有情况!
const int MAX=100010;
ll dp[1<<21];
ll a[MAX];
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>a[i];
int ans=0;
for(int i=0;i<(1<<n);i++){
int flag=1;
for(int j=0;j<n;j++){
if((i&(1<<j))==0)
{
dp[i|(1<<j)]=dp[i]+a[j];
if(dp[i|(1<<j)]<m)
flag=0;
}
}
if(flag&&dp[i]<m)
ans++;
}
cout<<ans;
}