洛谷传送门
Atcoder传送门
题目大意
给你N个整数 a1,a2,a3,...,aN a 1 , a 2 , a 3 , . . . , a N 和整数 K K , 定义一个数为不必要的当且仅当包含 ai a i 且 ∑ak∈Sak≥K ∑ a k ∈ S a k ≥ K 的所有集合 S S 去掉后集合内元素总和仍然 ≥K ≥ K 。 求不必要的数的个数。
输入输出格式
输入格式
第一行两个整数 N、K N 、 K 。
第二行 N N 个整数, 表示。
输出格式
一行一个整数, 表示不必要的数的个数。
数据范围
1≤N≤5000 1 ≤ N ≤ 5000 , 1≤K≤5000 1 ≤ K ≤ 5000 , 1≤ai≤109 1 ≤ a i ≤ 10 9
解题分析
显然不必要的数只会是从最小值开始的连续的一段, 所以我们排序后二分, 每次01背包判定是否是不必要的数即可。
复杂度 O(N2log(N))32 O ( N 2 l o g ( N ) ) 32 。 (据说正解是 O(N2) O ( N 2 ) ?反正博主不会写…而且暴力跑的贼快。)
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cmath>
#include <bitset>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 5050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c -48, c = gc;
}
std::bitset <MX> bt;
int num, kth, dat[MX];
IN bool check(const int &now)
{
bt.reset();
bt[0] = true; int bd = kth - dat[now];
for (R int i = 1; i <= num; ++i) if(i != now) bt |= bt << dat[i];
for (R int i = kth - 1; i >= bd; --i) if(bt[i]) return true;
return false;
}
int main(void)
{
in(num); in(kth);
for (R int i = 1; i <= num; ++i) in(dat[i]);
std::sort(dat + 1, dat + 1 + num);
int ans = 0, mid, lef = 1, rig = num;
W (lef <= rig)
{
mid = lef + rig >> 1;
if(!check(mid)) ans = mid, lef = mid + 1;
else rig = mid - 1;
}
printf("%d", ans);
}