题意:给定x轴上有n个点,每一个点都有一个权值,让在x轴上选一个点,求出各点到这个点的距离的三次方乘以权值最小。
析:首先一开始我根本不会三分,也并没有看出来这是一个三分的题目的,学长说这是一个三分的题,我就百度了一下什么是三分算法,一看感觉和二分差不多,当然就是和二分差不多,也是慢慢缩短范围。
这个题也这样,在最左端和最右端不断的三分,直到逼进那个点,刚开始我设置的误差eps是10负8,但是TLE了,我以为是太小,三分数太多,然后我又改成10负6还是TLE,我又失望了,干脆我不用误差了,我让它三分200次就结束,但一直是TLE,直到我改到20次,才AC。但实际并不是我设置的太小,而是我用了pow这个函数和fabs这个函数,这两个函数运行起来太慢了,导致我TLEn次,所以我不建议用这两个函数,完全可以自己写嘛,这样才会更快。
知道三分,这个题就很简单了,就是扫一下而已。
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <set> #include <map> #include <cmath> #include <string> #include <vector> using namespace std; typedef long long LL; const int maxn = 50005; const double eps = 1E-6; double x[maxn], w[maxn]; int n; double f(double mid){ double ans = 0.0; for(int i = 0; i < n; ++i) ans += pow(fabs(x[i] - mid), 3) * w[i]; return ans; } int main(){ int T, cases = 0; cin >> T; while(T--){ scanf("%d", &n); for(int i = 0; i < n; ++i) scanf("%lf %lf", &x[i], &w[i]); double r = x[n-1], l = x[0]; for(int i = 0; i < 30; ++i){ double mid_l = l + (r-l) / 3.0; double mid_r = r - (r-l) / 3.0; if(f(mid_l) < f(mid_r)) r = mid_r; else l = mid_l; } int ans1 = (int)floor(f(l)+0.5), ans2 = (int)floor(f(r)+0.5); int ans = min(ans1, ans2); printf("Case #%d: %d ", ++cases, ans); } return 0; }
这是我不用pow函数的代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <set> #include <map> #include <cmath> #include <string> #include <vector> using namespace std; typedef long long LL; const int maxn = 50005; const double eps = 1E-8; double x[maxn], w[maxn]; int n; double f(double mid){ double ans = 0.0; for(int i = 0; i < n; ++i){ double tmp = x[i] - mid; if (tmp < 0)tmp = -tmp; ans += tmp*tmp*tmp* w[i]; } return ans; } int main(){ int T, cases = 0; cin >> T; while(T--){ scanf("%d", &n); for(int i = 0; i < n; ++i) scanf("%lf %lf", &x[i], &w[i]); double r = x[n-1], l = x[0]; while(r - l > eps){ double mid_l = l + (r-l) / 3.0; double mid_r = r - (r-l) / 3.0; if(f(mid_l) < f(mid_r)) r = mid_r; else l = mid_l; } int ans1 = (int)floor(f(l)+0.5), ans2 = (int)floor(f(r)+0.5); int ans = min(ans1, ans2); printf("Case #%d: %d ", ++cases, ans); } return 0; }