题意
输入n,k分别表示n个a[i]体积物品,箱子最大容量为k,求第一种操作和第二种操作需要多少个箱子。
有两种操作,第一种操作是从1~i-1之间有没有可以放下第i个物体体积的箱子,箱子编号越前面越好
第二种操作1~i-1之间有没有可以放下第i个物体体积的箱子,使得箱子数最少。
思路
第二种操作很好想直接lower_bound的找1~i-1放的箱子(排好序从小到大)寻找合适的,没有合适就再整个箱子。multiset和map都可以用
然后比赛因为A题卡死,写了4半小时(害,带着队友一起脑淤血)导致最后半小时开B题思路混乱,根本没想到线段树可以nlgn查询,我甚至怀疑队友读错题了……
赛后想了一个build 建1~n 容量存k-a[i]的树,然后查询第i个是否有大于a[i]的值,如果有删掉第i位置的k-a[i],再去那个符合的位置减去a[i],如果没有就continue
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
#define rson(x) x<<1
#define lson(x) x<<1|1
const int N=1e6+10;
int po[N],a[N],tree[N<<2],wei[N<<2];
int n,k,cnt1,cnt2;
void build(int l,int r,int x){
if(l==r){
tree[x]=k-a[l];
wei[x]=l;
return;
}
int mid=(l+r)>>1;
build(l,mid,rson(x));
build(mid+1,r,lson(x));
tree[x]=max(tree[rson(x)],tree[lson(x)]);
if(tree[rson(x)]>=tree[lson(x)]){
wei[x]=wei[rson(x)];
}
else{
wei[x]=wei[lson(x)];
}
return ;
}
int pp;
void query(int l,int r,int x,int pos,int zhi){
if(zhi<=tree[x] && wei[x]<pos){
pp=min(pp,wei[x]);
}
if(l==r || pp<wei[x] || zhi>tree[x]){return;}
int mid=(l+r)>>1;
if(tree[rson(x)]>=zhi){
query(l,mid,rson(x),pos,zhi);
}
else if(tree[lson(x)]>=zhi){
query(mid+1,r,lson(x),pos,zhi);
}
}
void xiugai(int l,int r,int x,int pos,int zhi){
if(l==pos &&r==pos){
tree[x]-=zhi;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid){
xiugai(l,mid,rson(x),pos,zhi);
}
if(pos>mid){
xiugai(mid+1,r,lson(x),pos,zhi);
}
tree[x]=max(tree[rson(x)],tree[lson(x)]);
if(tree[rson(x)]>=tree[lson(x)]){
wei[x]=wei[rson(x)];
}
else{
wei[x]=wei[lson(x)];
}
return ;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
cnt1=n,cnt2=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
for(int i=2;i<=n;i++){
pp=n+2;
query(1,n,1,i,a[i]);
if(pp!=n+2){
cnt1--;
xiugai(1,n,1,pp,a[i]);
xiugai(1,n,1,i,k-a[i]);
}
}
map<int,int>mp;
map<int,int>::iterator it;
mp[k]=n;
for(int i=1;i<=n;i++){
it=mp.lower_bound(a[i]);
int zhi=it->first;
mp[zhi]--;mp[zhi-a[i]]++;
if(mp[zhi]==0){
mp.erase(it);
}
}
for(auto i:mp){
if(i.first==k){continue;}
cnt2+=i.second;
}
printf("%d %d
",cnt1,cnt2);
}
return 0;
}
水哥的猛思路
哎,如果没有疫情水哥估计银冲金了,而我三题打铁了,E题主席树赛后补题也卡死,比赛结论都没去想,c题题目都没读……
水哥思路直接建1~n全是k的,然后找到k就cnt1++,就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
#define lson(x) x<<1
#define rson(x) x<<1|1
const int N=1e6+10;
int po[N],sum[N],a[N],tree[N<<2],wei[N<<2];
int n,k,cnt1,cnt2;
void build(int l,int r,int x){
if(l==r){
tree[x]=k;return;
}
int mid=(l+r)>>1;
build(l,mid,lson(x));
build(mid+1,r,rson(x));
tree[x]=max(tree[rson(x)],tree[lson(x)]);
return ;
}
void xiugai(int l,int r,int x,int zhi){
if(l==r){
if(tree[x]==k)cnt1++;
if(tree[x]>=zhi)tree[x]-=zhi;
return ;
}
int mid=(l+r)>>1;
if(tree[lson(x)]>=zhi){
xiugai(l,mid,lson(x),zhi);
}
else if(tree[rson(x)]>=zhi){
xiugai(mid+1,r,rson(x),zhi);
}
tree[x]=max(tree[rson(x)],tree[lson(x)]);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
cnt1=0,cnt2=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
for(int i=1;i<=n;i++){
xiugai(1,n,1,a[i]);
}
map<int,int>mp;
map<int,int>::iterator it;
mp[k]=n;
for(int i=1;i<=n;i++){
it=mp.lower_bound(a[i]);
int zhi=it->first;
mp[zhi]--;mp[zhi-a[i]]++;
if(mp[zhi]==0){
mp.erase(it);
}
}
for(auto i:mp){
if(i.first==k){continue;}
cnt2+=i.second;
}
printf("%d %d
",cnt1,cnt2);
}
return 0;
}
orz
虽然补题到了五题,E题也抄模板过了,但好难受,比赛的时候可能策略出错了吧脑子也不够清醒,说到底还是菜,希望能变强吧