題目: 有2N個實數,不重複每次選取兩個數,一個向下取整,另一個向上取整, 求變化前後和值之差的 最小值。
分析: 這種題沒什麼特定的算法,比賽時看RP, 不是容易想到方法。
可以這樣考慮這個問題, 設實數對應的小數部分為X, 若向下取整 變化量為 -Xi, 若向上取整變化量為 +(1-Xj) ,總變化量為M*1+Sigma{ X } [ M是1的個數 ] (當然整數向上取整不變)
驚人的發現小數部分的變化情況都是去負号, 這樣我們隻需對所有的小數部分求和,為定值, 而決定變化量的是 1 的個數,(隻有對非正數向上取整才有1)
比如下面兩種情況:
(1) 1.2 2.0 3.0 4.0 (1最多一個,最少零個)
(2) 1.2 2.3 3.4 5.0 (1最多兩個,最少一個)
可以得到規律:1的個數總是在某個區間變化, 并可以取其中的任意值。 接下來隻需枚舉這些可能, 求變化量的最小值即可。
代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
const double eps=1e-20;
double a[5000];
int main()
{
double x,sum=0;
int N,cnt=0;
cin>>N;
for(int i=0;i<N*2;i++){
cin>>x;
double t=x-floor(x);
sum += t;
if(t>eps) cnt++;
}
double ans=1e10;
int u,v;
if(cnt<=N){
u=0; v=cnt;
}
else {
u=cnt-N; v=N;
}
for(int i=u;i<=v;i++){
ans=min(ans,abs(i-sum));
}
printf("%.3f\n",ans);
return 0;
}