1. 程式人生 > >[SCOI2010] 傳送帶 題解

[SCOI2010] 傳送帶 題解

比較神的一道題,以前沒有接觸過三分套三分...

介紹一下我的做法。

首先,碰見這種題,第一眼一般都不知道從何下手。這時候觀察題目的性質,發現所走的路徑一定是A到X到Y到D,其中X在[A,B]上,Y在[C,D]上.
所以很容易想到一個暴力演算法:把每一對[x,y]都列舉一遍即可。但是這樣的時間複雜度太高了,所以需要考慮別的辦法。

在手算模擬之後,可以發現[x,y]的列舉都是有規律性的,是一個類似函式的變化。所以考慮三分。

那麼怎麼三分呢?

考慮問題的簡化版。給你一個點,一條線段,求到哪個點最快,各種定義依據原問題的定義。

這時候很簡單,很明顯就是一個函式,可以三分。

那麼會發現,如果這個函式有單調性,那麼問題的簡化版也一定具有單調性。也就是說解也是有單調性的。

所以我們可以先三分X,再三分Y,最後選擇一個最優解即可。

 1 #pragma GCC optimize("O2")
 2 #include <bits/stdc++.h>
 3 #define PI 3.14159265
 4 #define DO_NOT_USE_SCANF ios::sync_with_stdio(0)
 5 #define PQ priority_queue
 6 #define lowbit(x) ((x) & (-x))
 7 #define lmy
 8 #ifdef lmy
 9     #define DEBUG printf("Passing [%s] in LINE %d...\n" , __FUNCTION__ , __LINE__)
10
#endif 11 typedef long long ll; 12 typedef unsigned long long ull; 13 14 using namespace std; 15 16 inline void read(int &x) { 17 int f = 1;x = 0;char ch = getchar(); 18 while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} 19 while(ch >= '0' && ch <= '
9') {x = x * 10 + ch - '0'; ch = getchar();} 20 x *= f; 21 } 22 23 inline void readll(ll &x) { 24 ll f = 1;x = 0;char ch = getchar(); 25 while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} 26 while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();} 27 x *= f; 28 } 29 30 struct Point { 31 double x , y; 32 }; 33 34 Point a , b , c , d; 35 36 double p , q , r; 37 38 const double eps = 1e-6; 39 double dist(Point a , Point b) { 40 return sqrt((a . x - b . x) * (a . x - b . x) + (a . y - b . y) * (a . y - b . y)); 41 } 42 43 double f(Point x , Point y) { 44 return dist(a , x) / p + dist(x , y) / r + dist(y , d) / q; 45 } 46 double task(Point x) { 47 Point l = c , r = d; 48 while(dist(l , r) > eps) { 49 Point delta = (Point){(r . x - l . x) / 3 , (r . y - l . y) / 3}; 50 Point lmid = (Point){l . x + delta . x , l . y + delta . y}; 51 Point rmid = (Point){r . x - delta . x , r . y - delta . y}; 52 if(f(x , rmid) - f(x , lmid) > eps) r = rmid; 53 else l = lmid; 54 } 55 return f(x , l); 56 } 57 58 59 void solve() { 60 scanf("%lf%lf%lf%lf" , &a . x , &a . y , &b . x , &b . y); 61 scanf("%lf%lf%lf%lf" , &c . x , &c . y , &d . x , &d . y); 62 scanf("%lf%lf%lf" , &p , &q , &r); 63 64 Point l = a , r = b; 65 while(dist(l , r) > eps) { 66 Point delta = (Point){(r . x - l . x) / 3 , (r . y - l . y) / 3}; 67 Point lmid = (Point){l . x + delta . x , l . y + delta . y}; 68 Point rmid = (Point){r . x - delta . x , r . y - delta . y}; 69 if(task(rmid) - task(lmid) > eps) r = rmid; 70 else l = lmid; 71 } 72 73 cout << fixed << setprecision(2) << task(l) << endl; 74 return; 75 } 76 int main(){ 77 #ifdef lmy 78 int nol_cl = clock(); 79 #endif 80 81 solve(); 82 83 // did you forget to undefine Lmy ? 84 #ifdef lmy 85 printf("\nTime: %dms\n", int((clock() - nol_cl) / (double)CLOCKS_PER_SEC * 1000)); 86 #endif 87 return 0; 88 }