农夫约翰将按字典序排列的 N 头奶牛的名字列表贴在了牛棚的门上。
每个奶牛的名字都由一个长度介于 1 到 20 之间的由小写字母构成的唯一字符串表示。
麻烦制造者贝茜将列表中的奶牛名字重新排序打乱了列表。
此外,她还对每头奶牛的名字中的字母顺序进行了重新排列(也可能保持不变)。
给定修改过后的列表,请帮助约翰确定列表中的每个名字可能出现在原始列表中的最低和最高位置。
输入格式
第一行包含整数
N
N
N。
接下来
N
N
N 行,按照修改过后列表的顺序,给出了修改过后的奶牛的名字。
输出格式
共
N
N
N 行,第 i 行输出给定的第 i 个字符串在原始列表中可能的最低和最高位置。
数据范围
1
≤
N
≤
50000
1≤N≤50000
1≤N≤50000
4
essieb
a
xzy
elsie
2 3
1 1
4 4
2 3
分析 :对于单个字符串来说,他的字典序越小他靠前的可能越大(假设总体位置不变),反之也成立,那么我们总可以通过逐字符将其调整到最小进行靠前排序,那么,对于所有字符串均进行此操作就得到了全体字符串的最小序 ,反之我们能得到最大序,又因为最优解>贪心解,我们想让最小序中字符串排名靠前,就让他去最大序中进行排名(即单个字符串贪心后在所有字符串再次贪心得到最优解)
因此,分别二分左右两个端点即可得到最高和最低位置
#include<bits/stdc++.h>
using namespace std;
//typedef pair<string , string> PII;
vector<string> mx , mn , mm;
int n;
int main()
{
cin >> n;
for (int i = 0; i < n; ++ i)
{
string x;
cin >> x;
mm.push_back(x);
sort(x.begin() , x.end());
mn.push_back(x);
reverse(x.begin() , x.end());
mx.push_back(x);
}
sort(mn.begin() , mn.end());
sort(mx.begin() , mx.end());
for (auto c : mm)
{
auto x = c;
sort(x.begin() , x.end());
int l = 0 , r = mm.size() - 1;
while(l < r)
{
int mid = l + r >> 1;
if (mx[mid] >= x) r = mid;
else l = mid + 1;
}
cout << l + 1 << " ";
reverse(x.begin() , x.end());
l = 0 , r = mm.size() - 1;
while(l < r)
{
int mid = l + r + 1 >> 1;
if (mn[mid] <= x) l = mid;
else r = mid - 1;
}
cout << r + 1 << endl;
}
return 0;
}
时间复杂度 ( n l o g n ∗ s r e l e n ( s ) ) (nlogn*srelen(s)) (nlogn∗srelen(s))