C. Petya and Exam
题目链接
题目大意,考试t个小时,n个题,简单题要用a个小时,难题要花b个小时,每题1分,可随时交卷,但考试过程中会随着时间的延长,题目会变成必做题,如果交卷时必做题没写,得0分;
所以时间太短会使写出的题太少而得不了高分,而时间太长则会让必做题变多,可能不得不做更多难题,甚至必做题写不完,最后需要找到一个最高分;
n大小2e5;
之前有几个思路,第一是二分答案,如果答案可行就找大的,不然找小的,这是没问题的,那就是判断合法,怎么决定时间,怎么选难题,简单题还有必做题,同时找时间不能二分,因为没有单调性,所以这是一个假思路了,只能用时间去求最大的答案。
如果知道时间,那就是把必做题写完,写不完就为答案0,写完,拿剩余时间去优先做剩余简单题,再写难题,必做题可以用前缀和预处理,时间很短,再然后就是找时间,时间最大1e9,但是n是2e5,并且只需要变成必做题时间的信息就够了,所以用vector存好每个时间点,必做题信息,时间就行了,不超过2e5,枚举是让时间等于下一个状态时间-1,做这个状态的必做题与剩余题。以下是代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
long long int T,n,t,a,b,p,suma,sumb,ans,sum,lint;
struct madoka{
long long int c;
long long int d;
}ma[200007];
struct homura{
long long int ez;
long long int df;
long long int d;
}lin;
vector<homura>ho;
bool cmp(madoka a1,madoka a2){
return a1.d<a2.d;
}
int main(){
scanf("%lld",&T);
while(T--){
ho.clear();
suma=0;
sumb=0;
scanf("%lld%lld%lld%lld",&n,&t,&a,&b);
for(int i=1;i<=n;i++){
scanf("%lld",&ma[i].c);
if(ma[i].c==0)suma++;
else{
sumb++;
}
}
for(int i=1;i<=n;i++){
scanf("%lld",&ma[i].d);
}
sort(ma+1,ma+1+n,cmp);
lin.d=ma[1].d-1;
lin.df=0;
lin.ez=0;
ho.push_back(lin);
lin.d=ma[1].d;
if(ma[1].c==0){
lin.ez=1;
lin.df=0;
}
else{
lin.ez=0;
lin.df=1;
}
for(int i=2;i<=n;i++){
if(ma[i].d==lin.d){
if(ma[i].c==0)lin.ez++;
else{
lin.df++;
}
}
else{
ho.push_back(lin);
lin.d=ma[i].d;
if(ma[i].c==0){
lin.ez++;
}
else{
lin.df++;
}
}
}
ho.push_back(lin);
lin.d=t;
ho.push_back(lin);
ans=0;
for(int i=0;i<ho.size()-1;i++){
sum=0;
p=ho[i+1].d-1;
if(i==ho.size()-2)p++;
if(p>=(ho[i].df*b+ho[i].ez*a)){
p-=ho[i].df*b+ho[i].ez*a;
sum+=(ho[i].df+ho[i].ez);
if(p>=(suma-ho[i].ez)*a){
p-=(suma-ho[i].ez)*a;
sum+=suma-ho[i].ez;
}
else{
lint=p/a;
p-=lint*a;
sum+=lint;
}
if(p>=(sumb-ho[i].df)*b){
p-=(sumb-ho[i].df)*b;
sum+=sumb-ho[i].df;
}
else{
lint=p/b;
p-=lint*b;
sum+=lint;
}
ans=max(sum,ans);
}
else{
continue;
}
}
printf("%lld\n",ans);
}
return 0;
}