农夫约翰将按字典序排列的 NN 头奶牛的名字列表贴在了牛棚的门上。
每个奶牛的名字都由一个长度介于 11 到 2020 之间的由小写字母构成的唯一字符串表示。
麻烦制造者贝茜将列表中的奶牛名字重新排序打乱了列表。
此外,她还对每头奶牛的名字中的字母顺序进行了重新排列(也可能保持不变)。
给定修改过后的列表,请帮助约翰确定列表中的每个名字可能出现在原始列表中的最低和最高位置。
输入格式
第一行包含整数 NN。
接下来 NN 行,按照修改过后列表的顺序,给出了修改过后的奶牛的名字。
输出格式
共 NN 行,第 ii 行输出给定的第 ii 个字符串在原始列表中可能的最低和最高位置。
数据范围
1≤N≤500001≤N≤50000
输入样例:
4
essieb
a
xzy
elsie
输出样例:
2 3
1 1
4 4
2 3
样例解释
无论如何,字符串 “a” 必然出现在原始列表中第一个,类似的,字符串 “xzy” 必然出现在原始列表中的最后一个。
而字符串 “essieb” 和 “elsie” 都有可能位于原始列表的第 22 位或第 33 位,这取决于它们的原始字母顺序。
例如,”bessie” 和 “elsie” 分别位于 2,32,3 位,”sisbee” 和 “ilees” 分别位于 3,23,2 位。
思路
先计算每个字符串的最大值与最小值放入一个整体数组中;自己的最小位置就是在所有的最大中进行二分;最大位置就是自己的最大值与其他人的最小值做二分;
#include <bits/stdc++.h>
using namespace std;
vector<string> a, b, c;
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
string s; cin >> s; a.push_back(s);
sort(s.begin(), s.end()); b.push_back(s);
string e; for(int i = s.size() - 1; i >= 0; i--) e += s[i]; c.push_back(e);
}
sort(c.begin(), c.end());
sort(b.begin(), b.end());
for(int i = 0; i < n; i++){
string A = a[i]; sort(A.begin(), A.end());
int l = 0, r = n - 1;
while(l < r) {
int mid = l + r >> 1;
if(A <= c[mid]) r = mid;
else l = mid + 1;
} printf("%d ", l + 1);
string x; for(int i = A.size() - 1; i >= 0; i--) x += A[i];
l = 0, r = n - 1;
while(l < r) {
int mid = l + r + 1 >> 1;
if(x >= b[mid]) l = mid;
else r = mid - 1;
}
printf("%d\n", l + 1);
}
return 0;
}