【AcWing 113】【交互】特殊排序——二分

(题面来自AcWing)

有N个元素,编号1.2..N,每一对元素之间的大小关系是确定的,关系不具有传递性。

也就是说,元素的大小关系是N个点与N*(N-1)/2条有向边构成的任意有向图。

然而,这是一道交互式试题,这些关系不能一次性得知,你必须通过不超过10000次提问来获取信息,每次提问只能了解某两个元素之间的关系。

现在请你把这N个元素排成一行,使得每个元素都小于右边与它相邻的元素。

你可以通过我们预设的bool函数compare来获得两个元素之间的大小关系。

例如,编号为a和b的两个元素,如果元素a小于元素b,则compare(a,b)返回true,否则返回false。

将N个元素排好序后,把他们的编号以数组的形式输出,如果答案不唯一,则输出任意一个均可。

数据范围

1N1000

  遇到的第一道交互题。看到N的范围考虑插入排序:我们每次在原序列中找出合适的位置,把新的数字插入。题中要求询问小于等于10000次,大约是NogN的范围,那么就来二分了。

  二分时每次check一下数组中当前元素ans[mid]与i的关系;如果i < ans[mid],则说明mid的左边一定存在一个位置k满足ans[k] > i && ans[k - 1] < i,否则左边的数都大于i,插入到第一个位置即可。同理,i > ans[mid]就往右边插入。因为是向下取整二分,最终得到的ans[l]是大于i的第一个数。注意特判ans[l]也小于i的边界。

代码:

  1. // Forward declaration of compare API.  
  2. // bool compare(int a, int b);  
  3. // return bool means whether a is less than b.  
  4.   
  5. class Solution {  
  6. public:  
  7.     vector<int> specialSort(int N) {  
  8.         vector<int> ans;  
  9.         ans.push_back(1);  
  10.         for (int i = 2; i <= N; ++i) {  
  11.             int l = 0, r = ans.size() - 1;  
  12.             while (l < r) {  
  13.                 int mid = l + r >> 1;  
  14.                 if (compare(i, ans[mid]))  
  15.                     r = mid;  
  16.                 else l = mid + 1;  
  17.             }  
  18.             ans.push_back(i);  
  19.             if (compare(ans[l], i)) continue;  
  20.             for (int j = ans.size() - 2; j >= l; --j)  
  21.                 swap(ans[j], ans[j + 1]);  
  22.         }  
  23.         return ans;  
  24.     }  
  25. };  

猜你喜欢

转载自www.cnblogs.com/TY02/p/11332505.html