在这个问题中,最初会给你一个空的多集。您必须处理两种类型的查询:
ADD x x x - 在多集合中添加一个等于 2 x 2x 2x 的元素;
GET w w w - 询问是否可以求当前多集的某个子集的和,并得到等于 w w w 的值。
输入
第一行包含一个整数 m ( 1 ≤ m ≤ 1 0 5 ) m ( 1≤m≤10^5 ) m(1≤m≤105) - 查询次数。
然后是 m m m 行,每行包含两个整数 t i 、 v i t_i 、 v_i ti、vi ,表示 i i i 次查询。如果是 t i = 1 t_i=1 ti=1 ,那么 i i i 次查询就是 ADD v i ( 0 ≤ v i ≤ 29 ) v_i ( 0≤v_i≤29 ) vi(0≤vi≤29).如果是 t i = 2 t_i=2 ti=2 ,那么 i i i 这条查询就是 GET v i ( 0 ≤ v i ≤ 1 0 9 ) v_i ( 0≤v_i≤10^9 ) vi(0≤vi≤109)。
输出
对于每个 GET 查询,如果可以选择总和等于 w w w 的子集,则打印 YES
;如果不可能,则打印 NO
。
虽然本题标上了Bitsmasks的标签,但是其实考查的是贪心。
首先明确贪心策略,如果我们想要用一堆2的某次方来表示出一个数,那么我们应该尽可能多的用大数。
怎么会如此 ?😃😃😃😃
因为小数能够表示的状态肯定会比大数多,例如如果你有无穷多的 1 1 1,那么你就能够表示各种数字,因为任意数字都可以拆分成多个 1 1 1,但是如果你有很多个 w w w,那你怎么也表示不了 9999 9999 9999。
也就是说如果保证小数最多的情况下这个数还是无法被表示出来的话,那么就肯定没有可能表示出来了。
(水平有限无法给出严谨数学证明)
CODE:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int st[30];signed main(){int m;cin >> m;while(m--){int t,v;cin >> t >> v;if(t == 1){st[v]++;}else{for(int i = 29;i >= 0;i--){int l = 0,r = st[i];while(l < r){int mid = l + r + 1 >> 1;if(mid * (1 << i) <= v)l = mid;else r = mid - 1;}v -= r *(1 << i);}if(!v)cout << "YES\n";else cout << "NO\n";}}return 0;
}