http://codeforces.com/gym/101246/problem/J
题意:给出n个点坐标,要使这些点间距相同的话,就要移动这些点,问最少的需要的移动距离是多少,并输出移动后的坐标。
思路:昨晚比赛确定的一点就是通过X分搜索去枚举间距,使得最后的移动距离最短。
不过使用的是二分,而且写的时候也只枚举了起点和终点,后面想了要枚举所有的点,但时间来不及。
因为间距的单调不会使得答案单调,间距过大过小都会使得最后的移动距离不是最优,所以是使用三分而不是二分,顺便重温一下三分。
1 while(fabs(r - l) > eps) { 2 double mid = (l + r) / 2.0; 3 double midd = (mid + r) / 2.0; 4 if(cal(mid, 0) > cal(midd, 0)) l = mid; 5 else r = midd; 6 } 7 double ans = cal(l, 0) > cal(r, 0) ? r : l;
对于每次三分,每次在n个点里面假设一个点不动,然后枚举完算一遍,取最优。
而且据说挺卡精度的,直接开了1e-12.
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 405 4 const double eps = 1e-12; 5 double num[N]; 6 int n, id; 7 8 double cal(double x, int flag) { 9 double res = 0, ans = 100000000; 10 for(int st = 1; st <= n; st++) { 11 res = 0; 12 for(int i = 1; i < st; i++) 13 res += fabs(num[st] - (st - i) * x - num[i]); 14 for(int i = st + 1; i <= n; i++) 15 res += fabs(num[st] + (i - st) * x - num[i]); 16 if(ans > res) ans = res, id = st; 17 } 18 return ans; 19 } 20 21 void solve() { 22 scanf("%d", &n); 23 for(int i = 1; i <= n; i++) scanf("%lf", &num[i]); 24 double l = 0, r = 100000000; 25 while(fabs(r - l) > eps) { 26 double mid = (l + r) / 2.0; 27 double midd = (mid + r) / 2.0; 28 if(cal(mid, 0) > cal(midd, 0)) l = mid; 29 else r = midd; 30 } 31 double ans = cal(l, 0) > cal(r, 0) ? r : l; 32 double res = cal(ans, 1); 33 printf("%.4f ", res); 34 for(int i = 1; i < id; i++) 35 printf("%.10f ", num[id] - (id - i) * ans); 36 printf("%.10f ", num[id]); 37 for(int i = id + 1; i <= n; i++) 38 printf("%.10f ", num[id] + (i - id) * ans); 39 } 40 41 int main() { 42 freopen("input.txt", "r", stdin); 43 freopen("output.txt", "w", stdout); 44 solve(); 45 return 0; 46 }