差分:2020CCPC秦皇島 D Exam Results

今天也吃瓜發表於2020-12-19

題目連結:點選這裡

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
//差分性質:1.差分序列求字首和可得到原序列
//2.原序列[l,r]區間內所有元素+k,轉化為差分序列l處+k,r+1處-k; 
//對於每一個分數,都有一個分數上限和分數下限,在這個區間內的所有分數都可以使它及格
//可很顯然,1<=bi<=ai<=1e9,爆記憶體
//開一個陣列儲存一下每個分數上下限,用lower_bound定位對應分數下限或上限的下標, 
//及格就讓這個區間內的每個分數對應的及格人數+1(用差分陣列這個時間複雜度為O(1))
//現在每個分數對應的及格人數有了,遍歷一遍分數找到及格最多的人數即可
//注意由於是以最高分為標準的,也就是要從差成績中最高的開始算起
using namespace std;
typedef long long ll;
ll ans[800005],diff[800005],a[200005],b[200005];
int main(){
    int t;
    scanf("%d",&t);
    for(int hy=1;hy<=t;++hy){
    	ll n,p,cnt=0,sum=0,kk=0,ok=0;
    	scanf("%lld%lld",&n,&p);
    	for(ll i=0;i<=4*n+2;++i) diff[i]=0;
    	for(ll i=0;i<n;++i){
    		scanf("%lld%lld",&a[i],&b[i]);
    		ans[cnt++]=b[i],ans[cnt++]=b[i]*100/p,ans[cnt++]=a[i],ans[cnt++]=a[i]*100/p;
    		if(b[i]>ok) ok=b[i];
		}
		sort(ans,ans+cnt);//logn
		for(ll i=0;i<n;++i){//nlogn  //把符合的區間人數+1 
			ll minn=b[i],minm=b[i]*100/p,maxn=a[i],maxm=a[i]*100/p;
			ll pos1=lower_bound(ans,ans+cnt,minn)-ans;//低分數下限 
			ll pos2=lower_bound(ans,ans+cnt,minm)-ans;//低分數上限 
			ll pos3=lower_bound(ans,ans+cnt,maxn)-ans;//高分數下限 
			ll pos4=lower_bound(ans,ans+cnt,maxm)-ans;//高分數上限
			if(pos2<pos3){
				++diff[pos1],--diff[pos2+1],++diff[pos3],--diff[pos4+1];
			}// [pos1,pos2] 和 [pos3,pos4] 區間內+1 
			else{
				++diff[pos1],--diff[pos4+1];
			}//[pos1,po4]區間內+1 
		}
		for(ll i=0;i<cnt;++i){
			sum=sum+diff[i];
			if(ans[i]>=ok&&sum>kk){
				kk=sum;
			}//保證取到的是最高分(不然以最低分為標準肯定都會及格,人數最多)
		}
		printf("Case #%d: %lld\n",hy,kk);
	}
    return 0;
}

相關文章