题目描述
Professor Alex is preparing an exam for his students now.
There will be n students participating in this exam. If student i has a good mindset, he/she will perform well and get a
i
points. Otherwise, he/she will get b
i
points. So it is impossible to predict the exam results. Assume the highest score of these students is x points. The students with a score of no less than x⋅p% will pass the exam.
Alex needs to know what is the maximum number of students who can pass the exam in all situations. Can you answer his question?
题意:
有n个人,每个人在状态好和不好时会得到两个成绩
及格线为最高分的p%,问最多几个人及格
题解:
方法很巧妙
用尺取的方法
首先将所有成绩(包括状态好和不好)排序
然后先从第一个成绩开始选出包含五个人的最小区间
然后从头指针head和尾指针tail
head不断判断是否满足条件
while(a[head].val*100<a[tail].val*p)
因为成绩是顺序排的,所以tail指向的成绩为最高成绩
然后从最低开始移动判断,如果不满足且区间内值包含他的一次成绩,就删去
因为每个人有两个成绩,好成绩一定排在坏成绩前面
具体看看图
详细看代码
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int mx=1000010; struct node{ int id; ll val; }a[mx]; int vis[mx]; ll n,p; bool cmp(node q,node m) { return q.val<m.val; } int main(){ int t; cin>>t; for(int ca=1;ca<=t;ca++){ cin>>n>>p; int tot=0; ll x,b; for(int i=1;i<=n;i++){ cin>>x>>b; a[++tot]={i,x}; a[++tot]={i,b}; vis[i]=0; } cout<<"Case #"<<ca<<": "; // sort 按照从小到大排序 sort(a+1,a+1+tot,cmp); // now 表示当前 head 到 tail 这个范围中有多少个不同的节点 int now=0; int head=1,tail=0; // 尺取,先跑一个长度为 n的范围 while(now!=n){ tail++; if(vis[a[tail].id]==0){ now++; } vis[a[tail].id]++; } // 答案最少有一个。 int ans=1; // 因为 进入 while 需要先加 所以要提前的 减一下 now--; vis[a[tail].id]--; tail--; while(tail<tot){ // 尾指针向后移动一下 tail++; // 如果 这个数前面已经将去过了,头结点到这个范围没有 now++ if(vis[a[tail].id]==0){ now++; } vis[a[tail].id]++; // 进行尺取,只要不满足的就减去 while(a[head].val*100<a[tail].val*p){ // 如果当前区间这个 id 的数就剩一个还不满足就 now-- if(vis[a[head].id]==1){ now--; } vis[a[head].id]--; head++; } // 更新最大值 ans=max(ans,now); } cout<<ans<<"\n"; } return 0; }