题目链接
https://codeforces.com/problemset/problem/351/A
题目大意
给你一个2×n长的序列,进行n次操作,每次操作是选取两个从未选过的数,一个取上整,一个取下整,问你最后能得到最接近原来和的序列是多少。
解题思路
大佬题解写的***简单,我理解了好一会儿。
对于每个非整数,可以选择向下取整,也可以选择向上取整;
假设数i的小数部分为x,比如i=1.234,则x=0.234,
如果i向下取整,我们规定向下取整丢失的小数部分要加到答案上,即ans+=x;
如果i向上取整,ans-=1-x,还是上面的例子,若i=1.234向上取整,导致多加了1-0.234,因此,我们规定多加的要从ans中减去,即ans-=1-x,转化为ans+=-(1-x),再转化为ans+=x-1。
对比一下向下取整和向上取整,我们发现,它们对ans造成的影响区别只在向上取整时多减了1。
假设i的小数部分为x,当i向下取整时,ans+=x,对此时的ans-=1,就是i向上取整时对ans的影响。
因此,我们可以把全部的小数部分加起来,这表示全部的数都向下取整与原数之和的差值;
枚举向上取整数的数量,已经求出向下取整与原数之和的差值了,那么,加了多少个1就代表有多少个数从向下取整转变为向上取整;
每次枚举,都判断统计最小ans。
向下取整的数目的枚举范围[max(0,n-cnt0),min(n,2*n-cnt0)],
可以理解为n对数,cnt0个整数,对于整数而言,向上向下取整都无所谓;
左端点:当整数的数目不超过n的时候,就让全部整数向上取整,总共就只能让n个数向上取整,所以就剩下n-cnt0个非整数的数可以向上取整了;当整数的数目超过n时,向上取整的数可以全部为整数,这样,非整数的数中向上取整的数的数目就为0了。
右端点:当序列中无整数时,即全为非整数,非整数中可以向上取整的数目为n个;当序列中整数数目大于n时,整数中n个向下取整,cnt0-n个向上取整,所以非整数全部向上取整,即2n-cnt0。
AC代码
#include<bits/stdc++.h> using namespace std; int n,cnt0; const double eps = 1e-8; double ans=4e7+100,x,sum; int main(){ scanf("%d",&n); for(int i=1;i<=2*n;i++) { scanf("%lf",&x);//用数组就TLE double ttt=x-floor(x); if(ttt==0) cnt0++; else sum+=ttt; } for(int i=max(0,n-cnt0);i<=min(n,2*n-cnt0);i++){ ans=min(ans,fabs(sum-i)); } printf("%.3lf\n",ans); }