- Quiz
- AC
- 解法
- 半分全列挙
- N=40なので20, 20に分割すればそれぞれの列挙は220=106程度
- 片側を全列挙、片側を二分探索、という形が多い?今回はそれ
- 分割したそれぞれを「前半部」「後半部」と呼ぶとして、後半部は二分探索用にソートしておく
VV f(VI& A){
ll N = SZ(A);
VV G(N+1);
rep(f,1<<N){
ll sum=0;
ll cnt=0;
rep(i,N){
if(f>>i&1){
sum += A[i];
cnt++;
}
}
G[cnt].push_back(sum);
}
rep(i,N+1){
SORT(G[i]);
}
return G;
}
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
ll N,K,L,R;
cin>>N>>K>>L>>R;
ll N0 = N/2;
ll N1 = N-N0;
VI A(N);
rep(i,N)cin>>A[i];
VV G,F;
{
VI B;
rep(i,N0)B.push_back(A[i]);
G = f(B);
}
{
VI B;
FOR(i,N0,N)B.push_back(A[i]);
F = f(B);
}
ll cnt=0;
rep(i,N0+1){
for(ll value : G[i]){
ll j = K-i;
if(j<0) continue;
if(j==0){
if(L<=value and value<=R)cnt++;
}else{
if(j>N1)continue;
ll left = L-value;
ll right = R-value;
auto it = lower_bound(ALL(F[j]), left);
auto it2 = upper_bound(ALL(F[j]), right);
ll num = it2-it;
cnt += num;
}
}
}
p(cnt);
return 0;
}
類題