https://vjudge.net/problem/UVA-1612
题目
有 $n$ ($n\leqslant 16384$)位选手参加变成比赛。比赛有三道题目,每个选手的每道题目都有一个系统评测之前的预得分,接下来是系统测试。如果某道题目未通过系统测试,则该题的实际得分为0分,否则得分等于预得分。得分相同的选手,ID小的排前面。
问是否能给出所有 $3n$ 个得分以及最后的实际名次。如果可能,输出最后一名的最高可能得分。每个预得分均为小于1000的非负整数,保留两位小数。
题解
只管分数……那么对了哪些题就不重要了。
首先预处理得出 $2^3$ 种分数……
需要考虑两种情况,为了得到最高可能得分,
后面的那个人如果id比前面那个人id大,那么就得小于等于前一个人的分数。
否则就得小于前一个人的分数
二分查找很烦……如果没有深入理解根本不知道怎么写(所以应该看邓公的课……)
可以用两种划分模式($r$包含在右边的区间,查找区间为$[l,r)$)
二分查找的时候需要保证选择的划分模式一直正确……
如果是查找小于等于$x$的元素,那么第一种很麻烦……因为等于$x$的元素可能不存在,也可能存在,区间大小收缩到0后左边和右边的都要考虑……因此我们应该用第二种划分
如果是查找小于$x$的元素,那么最好用第一种……因为如果等于$x$的元素存在,那么还需要向前继续寻找,多此一举,还容易写错……
具体还是看邓公的课……
AC代码
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") #include<bits/stdc++.h> using namespace std; #define REP(r,x,y) for(register int r=(x); r<(y); r++) #define REPE(r,x,y) for(register int r=(x); r<=(y); r++) #ifdef sahdsg #define DBG(...) printf(__VA_ARGS__) #else #define DBG(...) #endif template<class T> inline void read(T &x) { char ch = getchar(); x=0; int f=1; while(!isdigit(ch) && ch!='-') ch=getchar(); if(ch=='-') f=-1,ch=getchar(); while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); } x*=f; } #define MAXN 26384 double sco[MAXN][3]; int pl[MAXN]; vector<double> scop[MAXN]; inline double findleq(double x, int i) { int l=0, r=scop[i].size(); while(l<r) { int mid=(l+r)>>1; if(scop[i][mid]-x<=1e-6) l = mid+1; else r=mid; } if(l<=0) return -1; l--; return scop[i][l]; } inline double findl(double x, int i) { int l=0, r=scop[i].size(); while(l<r) { int mid=(l+r)>>1; if(scop[i][mid]-x<-1e-6) l = mid+1; else r=mid; } if(l<=0) return -1; l--; return scop[i][l]; } int main() { #ifdef sahdsg freopen("in.txt", "r", stdin); #endif int n; int kase=0; while(~scanf("%d", &n) && n) { kase++; REP(i,0,n) { scop[i].clear(); REP(j,0,3) scanf("%lf", &sco[i][j]); REP(x,0,1<<3) { double k=0; REP(j,0,3) { if(x&(1<<j)) { k+=sco[i][j]; } } scop[i].push_back(k); } sort(scop[i].begin(), scop[i].end()); } REP(i,0,n) { read(pl[i]); } double mxs = sco[pl[0]-1][0]+sco[pl[0]-1][1]+sco[pl[0]-1][2]; int lstid = pl[0]; REP(i,1,n) { int nid = pl[i]; if(nid>=lstid) mxs = findleq(mxs,nid-1); else mxs = findl(mxs,nid-1); if(mxs<0) goto _wa; lstid = nid; } printf("Case %d: %.2f\n", kase, mxs); continue; _wa: printf("Case %d: No solution\n", kase); } return 0; }