C. Petya and Exam

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值