审题胜利
题意:在给定时间st内考试,可提前交卷。简单题0耗时a min,难题1耗时b min。每个题目有规定时间,在规定时间前未完成则成绩为0。问最大的做题数量。
思路:
一开始没读懂题意,膨胀到极致样例都不分析直接上来就写。
因为时间t范围1e9,考虑离散化后用前缀和统计每个时间节点的0、1题目个数。遍历枚举提前交卷的时间,判断是否合法,记录答案ans。
贪心注意点1:题目存在强制性与非强制性,所以在合法后可能存在还有时间剩余的情况,这时可以在后面限制时间更大的数字中拿。因为a<b,所以贪心先把剩下的0拿完,然后有剩余的再去拿1。
贪心注意点2:在枚举交卷的时间节点时候,要让剩余时间尽可能大。所以枚举的时间节点是下一个vis数组(顺序存放每个出现过的限制时间节点)中的限制时间-1
再上手就码就可以锤了o
struct node{
int f,t;
}a[maxn];
bool cmp(node a,node b){
return a.t<b.t;
}
int main(){
int m=ird();
while(m--){
map<int,int> mp0,mp1,vis;
int n=ird(),st=ird(),aa=ird(),b=ird();
for(int i=1;i<=n;i++){
a[i].f=ird();
}
for(int i=1;i<=n;i++){
a[i].t=ird();
}
sort(a+1,a+1+n,cmp);
int sum=0,c0=0,c1=0;
vis[0]=-1;//注意ti=0的情况是存在的
for(int i=1;i<=n;i++){
if(a[i].t!=vis[sum]){
vis[++sum]=a[i].t;//离散
}
if(a[i].f)
c1++;
else
c0++;
mp0[a[i].t]=c0;
mp1[a[i].t]=c1;//前缀和统计
}
vis[++sum]=st;
mp0[st]=c0;
mp1[st]=c1;
int ans=0;
for(int i=0;i<=sum;i++){
int tt=vis[i],tc=0,tst=max(tt,vis[i+1]-1);//tst枚举的最大时间节点
if(1ll*aa*mp0[tt]+1ll*b*mp1[tt]<=1ll*tst){
tc=mp0[tt]+mp1[tt];
tst-=aa*mp0[tt]+b*mp1[tt];
}
else
continue;//直接就是0
if(tst/aa>0){
int g=min(tst/aa,c0-mp0[tt]);
tc+=g;
tst-=aa*g;
}//从0开始拿剩下的
if(tst/b>0){
tc+=min(tst/b,c1-mp1[tt]);
}
ans=max(ans,tc);
}
cout<<ans<<endl;
}
return 0;
}