好吧。。比赛的时候没有做出来。
主要是只考虑了所有整数都取向下的情景,没有考虑到所有整数都往上取。
首先区分出整数和小数,整数的差是没有影响的,主要在于小数的差。先把所有小数的和求出来。
因为取上为n个,取下为n个。对于所有小数来说哪一个小数取上和哪一个小数取下是没有区别的。假设0.3 0.5 0.7 0.8 ...假设里面有2个可以取上,2个可以取下。
无论是哪2个取上取下最后一定是0 + 0 + 1 + 1 = 2的结果。假设都是小数就好做了,因为2 * n个小数取上取下结果一定是n。
现在加入了整数,整数取上取下是没有区别的,所以小数取的和就不一定是n了,可以在n的周围进行变化,多一个整数就可以向下浮动1,或者向上浮动1。
如上面的0.3 0.5 0.7 0.8 0.6 3。多了0.6 和3。现在取4个上,4个下,要全是小数结果是4,但3是整数。3取上则小数多可以取一个下,结果就少1,3取下,小数就可以多一个
取上的,结果就多1.
那么有k个整数,(整数个数小于一半 < n) k个整数全取上的话,小数部分就可以只选取n - k个上,其余全下,那么和就是n - k
k个整数全取下的话,小数部分就可以只选取n - k个下,其余全上,那么和就是n,和可以在n - k到n之间波动。
同理整数个数多于一半 > n, n个全取上的话,小数部分全下,为 0,
n个全取下的话,小数部分全部为1,2 * n - k。
AC代码:
#include <cstring>
#include <cstdio>
#include <cmath>
const int MAX_NUMBER = 4006;
const double INF = 10000000.0;
const double eps = 1e-10;
double value[MAX_NUMBER];
int n, integer_number;
double sums_1;
int main() {
scanf("%d", &n);
integer_number = 0;
sums_1 = 0;
for (int i = 1; i <= 2 * n; i++) {
scanf("%lf", &value[i]);
if (fabs(value[i] - (int)value[i]) < eps) {
integer_number++;
}
else {
sums_1 += value[i] - (int)value[i];
}
}
double ans = INF;
if (integer_number > n) {
for (int i = 0; i <= 2 * n - integer_number; i++) {
double temp = fabs(i - sums_1);
if (temp < ans) {
ans = temp;
}
}
}
else {
for (int i = n - integer_number; i <= n; i++) {
double temp = fabs(i - sums_1);
if (temp < ans) {
ans = temp;
}
}
}
printf("%.3lf\n", ans);
return 0;
}