枚举间距会发现,如果间距过大或过小都会让答案太大。所以可以得出答案关于点间距的函数应该是个凹函数。
一开始怎么跑都超时, 后来强制跑了300次WA23 700次就过了。
××这次学会了强制让二分和三分缩小查找次数。
××范围 和强制对的次数都比较重要。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=505;
const double eps = 1e-15;
double p[N];
int n;
int chan;
double mbs(double a){
return a>=0?a:-a;
}
double check(double X){
double ans = inf;
for(int i=1;i<=n;i++){
double tpans = 0;
for(int j=1;j<i;j++){
tpans += mbs(p[i] - (i - j)*X - p[j]);
}
for(int j=i+1;j<=n;j++){
tpans += mbs(p[i] + (j - i)*X - p[j] ) ;
}
if(tpans < ans){
ans = tpans;
chan = i;
}
}
return ans;
}
int main() {
// freopen("input.txt", "r", stdin);
// freopen("output.txt","w", stdout);
scanf("%d", &n);
for(int i=1;i<=n;i++){
scanf("%lf",&p[i]);
}
double l = 0, r = 1000000.0;
int cnt = 700;
while(eps<mbs(r - l) && cnt--){
double mid = (l+r)/2;
double midd = (mid + r)/2;
if(check(mid) > check(midd)+eps){
l = mid;
}
else r = midd;
}
l = check(l)>check(r)?r:l;
double ans = check(l);
printf("%.4f\n", ans);
for(int i=1;i<chan;i++){
printf("%.10f ", p[chan] -(chan-i)*l);
}
printf("%.10f ", p[chan]);
for(int i=chan+1;i<=n;i++){
printf("%.10f ",p[chan]+(i-chan)*l);
}
return 0;
}