https://codeforces.com/gym/102770/problem/B
给定n个物品,一种背包(容量c)
求2种方法放物品,各要多少个背包
1.从左到右放,如果都不满足就加一个背包
分析一下,从左到右,线段树二分,如果左子树最大值可以装下物品就往左边递归,不行就往右边,递归终点必然是一个位置,标记这个位置的背包被用过了,因为a[i]<c 所以sum<=n*c,开(1-n)的线段树即可
2.找到最小且可以装下的背包,没有就加一个背包
找到最小且要能装下,我们维护一个单调增的背包顺序,然后二分能装下的位置,如果在背包最后面就是没有能满足的增加一个背包即可,stl中map是有序的,用map存储再加上map二分即可
// Problem: B. Bin Packing Problem
// Contest: Codeforces - The 17th Zhejiang Provincial Collegiate Programming Contest
// URL: https://codeforces.com/gym/102770/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<map>
using namespace std;
const int N=1e6+9;
int a[N];
int n,c;
//线段树
struct SEG{
#define INF (1<<31)
#define ll long long
#define tl(id) (id<<1)
#define tr(id) (id<<1|1)
struct node{
ll mx,tag,num;
}seg[N<<2];
bool inrange(int L,int R,int l,int r){return l<=L && R<=r;}
bool outofrange(int L,int R,int l,int r){return L>r || R<l;}
void pushup(const int id){
seg[id].mx=max(seg[tl(id)].mx,seg[tr(id)].mx);
seg[id].num=seg[tl(id)].num+seg[tr(id)].num;
}
void build(const int id,int l,int r){
seg[id].tag=0;
if(l==r){
seg[id].mx=c;
seg[id].num=0;
return;
}
int mid=(l+r)>>1;
build(tl(id),l,mid);
build(tr(id),mid+1,r);
pushup(id);
}
void maketag(int id,int l,int r,ll v){
seg[id].num=1;
seg[id].tag+=v;
seg[id].mx+=v;
}
void pushdown(int id,int l,int r){
int mid=(l+r)>>1;
maketag(tl(id),l,mid,seg[id].tag);
maketag(tr(id),mid+1,r,seg[id].tag);
seg[id].tag=0;
}
ll query(int id,int L,int R,int l,int r){
if(inrange(L,R,l,r)){
return seg[id].mx;
}else if(!outofrange(L,R,l,r)){
int mid=(L+R)>>1;
pushdown(id,L,R);
return query(tl(id),L,mid,l,r)+query(tr(id),mid+1,R,l,r);
}else{
return 0;
}
}
ll ask(int id,int l,int r,ll v){
if(l==r){
return l;
}
int mid=(l+r)>>1;
if(seg[tl(id)].mx>=v){
return ask(tl(id),l,mid,v);
}else{
return ask(tr(id),mid+1,r,v);
}
}
void modify(int id,int L,int R,int l,int r,ll x){
if(inrange(L,R,l,r)){
maketag(id,L,R,x);
}else if(!outofrange(L,R,l,r)){
int mid=(L+R)>>1;
pushdown(id,L,R);
modify(tl(id),L,mid,l,r,x);
modify(tr(id),mid+1,R,l,r,x);
pushup(id);
}
}
void update(int id,int l,int r,int pos,ll x){
if(l==r){
seg[id].mx+=x;
seg[id].num=1;
return;
}
int mid=(l+r)>>1;
if(mid>=pos){
update(tl(id),l,mid,pos,x);
}else{
update(tr(id),mid+1,r,pos,x);
}
pushup(id);
}
}t;
void solve(){
cin>>n>>c;
for(int i=1;i<=n;i++){
cin>>a[i];
}
ll ff=0;
ll bf=0;
//1 ff
t.build(1,1,n);
for(int i=1;i<=n;i++){
ll tt=t.ask(1,1,n,a[i]);
t.update(1,1,n,tt,-a[i]);
}
ff=t.seg[1].num;
//2 bf
map<int,int> mp;
for(int i=1;i<=n;i++){
auto tt=mp.lower_bound(a[i]);//二分找是否存在满足
if(tt!=mp.end()){//有
tt->second--;//减去一个
mp[tt->first-a[i]]++;//放入
if(tt->second==0){//删除无效数据
mp.erase(tt);
}
}else{
mp[c-a[i]]++;//没有满足的增加一个背包
bf++;
}
}
cout<<ff<<" "<<bf<<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}