題目鏈接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1112
題意:中文題誒~
思路:對於函數 f(x) = a + kx,對於x足夠大的情況下,顯然f(x)的值的相對大小是只受 k 影響的.對於 n 條這樣的直線最多可以發生 (n-1)*n/2 次超越;
不過本題只要求輸出前 1e4 次超越,所以可以先二分出1e4次超越的時間點(這部分是用來優化常數的),然後再枚舉每一次超越即可.這樣的時間復雜
度爲 O(n^2),對於 1e4 的數據量只要常數小一點還是能過的...
代碼:
1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 using namespace std; 5 6 const int MAXN = 1e4+10; 7 const int inf = 1e4; 8 pair<int, int> p[MAXN];//存儲開始時的數據 9 pair<int, int> p1[MAXN];//存儲1e4時間點的數據 10 pair<double, pair<int, int> > p2[MAXN*10];//存儲答案 11 int vis[MAXN*10], n; 12 13 int get_times(int mid){ //計算在k時間點可以達到的超越次數 14 int ans = 0; 15 for(int i=0; i<n; i++){ 16 p1[i].first = p[i].first + p[i].second * mid; 17 p1[i].second = i; 18 } 19 sort(p1, p1+n); 20 for(int i=0; i<n; i++){ 21 if(p1[i].second < i){ 22 ans += i-p1[i].second; 23 } 24 } 25 return ans; 26 } 27 28 void get_time(void){ //二分出達到1e4次超越的時間點 29 int l=0, r=MAXN*10; 30 int ans=0; 31 while(l < r-1){ 32 int mid = (l+r)>>1; 33 int cnt = get_times(mid); 34 if(cnt == inf) break; 35 else if(cnt > inf) r = mid; 36 else l = mid; 37 } 38 } 39 40 int main(void){ 41 scanf("%d", &n); 42 for(int i=0; i<n; i++){ 43 scanf("%d%d", &p[i].first, &p[i].second); 44 vis[p[i].first] = i+1; 45 } 46 sort(p, p+n); 47 get_time(); 48 int indx=0; 49 for(int i=0; i<n; i++){ 50 int a2 = p[p1[i].second].first; 51 for(int j=0; j<i; j++){ 52 int a1 = p[p1[j].second].first; 53 if(a1 > a2){ 54 int b1 = p[p1[j].second].second; 55 int b2 = p[p1[i].second].second; 56 double k = (a1-a2)*1.0/(b2-b1); //本次超越的時間點 57 p2[indx].first = k; 58 p2[indx].second.first = vis[a2]; 59 p2[indx++].second.second = vis[a1]; 60 } 61 } 62 } 63 if(!indx){ 64 printf("No Solution\n"); 65 }else{ 66 sort(p2, p2+indx); 67 int cnt = min(indx, inf); 68 for(int i=0; i<cnt; i++){ 69 printf("%d %d\n", p2[i].second.first, p2[i].second.second); 70 } 71 } 72 return 0; 73 }
时间: 2024-10-10 02:41:52