传送门:http://arc070.contest.atcoder.jp/tasks/arc070_b?lang=en
题意:
对于一个数组的任意一个子集,如果它的元素和大于等于K这个子集就叫做good subset,如果将一个数所在的所有good subset都减去这个数,这些集合依旧是good subset那么这个数被称为无用数。现在给定一个数组,求其中的无用数的个数。
题解:
如果一个数不是无用数,那么所有大于等于这个数的数都不会是无用数,那么我们先对这个数组进行排序,每次二分结果就行了。
如果当前的mid>=k,那么这个数肯定不是无用数(考虑集合中只有这一个元素的情况)。对于mid<k的这些数,我们只需将这个数去掉,查看在数组中所构成的所有集合的和是否存在属于[k-a[mid],k-1]的数。暴力求肯定会超时(O(n^3longn))。。。。
对于上面的求和的过程我们可以通过bitset来优化,每次用sum|=sum<<a[i]来计算,最后for一遍s[sum[k-a[mis]],sum[k-1]]是否存在1就行了。
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long LL; const double eps = 1e-10; const int maxn = 5000+100; int n,k,a[maxn]; bitset<maxn> sum; bool judge(int x) { if(a[x]>=k)return 1; sum.reset(); sum[0]=1; for(int i=1;i<=n;++i) if(i!=x)sum|=sum<<a[i]; for(int i=k-1;i>=k-a[x];--i) if(sum[i]) return 1; return 0; } void solve() { int l=0,r=n+1; while(l<r) { int mid=l+r>>1; if(judge(mid)) r=mid; else l=mid+1; } cout << l-1 << endl; } int main() { #ifdef ac freopen("in.txt" , "r" , stdin); // freopen("out.txt" , "w" , stdout); #endif cin >> n >> k; for(int i=1;i<=n;++i) cin >> a[i]; sort(a+1, a+n+1); solve(); return 0; }
时间: 2024-10-10 22:00:20