题意:
有n (n<16345)个人,每个人有三个数(小于1000且最多两位小数点),表示答对对应题的得分。规定总分越高的人rank越高。总分相同,id小的rank高。现在知道rank,问这个rank是否可能,如果可能,那么rank最小的那个人的最大得分是多少。
思路:
3个数,最多8种情况。然后从rank小往上推,每次选择一个最小的能符合条件的分数,当作这个人的分数。如果能推下去,则ok,否则,不能。
坑点:
精度很坑。转成整数才过了。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define N 20000 struct Man{
int a[];
int possible[];
void read() {
for (int i = ; i < ; i++) {
double tmp;
scanf("%lf", &tmp);
a[i] = (int)((tmp+1e-)*);
}
for (int i = ; i < ; i++) {
int sum = ;
for (int j = ; j < ; j++) {
if ((i>>j)&) {
sum += a[j];
}
}
possible[i] = sum;
}
sort(possible, possible+);
}
}man[N];
int rk[N];
int n; bool dfs(int pre, int id) {
if (id <= ) return true;
int minres = 0x3f3f3f3f;
bool isok = false;
for (int i = ; i >= ; i--) {
if (man[rk[id]].possible[i] > pre || (man[rk[id]].possible[i] == pre && rk[id] < rk[id+])) {
isok = true;
minres = min(minres, man[rk[id]].possible[i]);
} else break;
}
if (!isok) return false; return dfs(minres, id-);
} int main() {
int cas = ;
while (scanf("%d", &n)!=EOF) {
if (n == ) break;
printf("Case %d: ", cas++);
for (int i = ; i <= n; i++) {
man[i].read();
}
for (int i = ; i <= n; i++) {
scanf("%d",&rk[i]);
} int ans = -;
for (int i = ; i < ; i++) {
if (dfs(man[rk[n]].possible[i], n-)) {
ans = max(ans, man[rk[n]].possible[i]);
} else break;
} if (ans == -) {
puts("No solution");
} else {
printf("%.2f\n", ans/100.0);
}
}
return ;
}