0
点赞
收藏
分享

微信扫一扫

AcWing 1996. 打乱字母(贪心,二分)

【题目描述】
农夫约翰将按字典序排列的 N N N头奶牛的名字列表贴在了牛棚的门上。
每个奶牛的名字都由一个长度介于 1 1 1 20 20 20之间的由小写字母构成的唯一字符串表示。
麻烦制造者贝茜将列表中的奶牛名字重新排序打乱了列表。
此外,她还对每头奶牛的名字中的字母顺序进行了重新排列(也可能保持不变)。
给定修改过后的列表,请帮助约翰确定列表中的每个名字可能出现在原始列表中的最低和最高位置。

【输入格式】
第一行包含整数 N N N
接下来 N N N行,按照修改过后列表的顺序,给出了修改过后的奶牛的名字。

【输出格式】
N N N行,第 i i i行输出给定的第 i i i个字符串在原始列表中可能的最低和最高位置。

【数据范围】
1 ≤ N ≤ 50000 1≤N≤50000 1N50000

【输入样例】

4
essieb
a
xzy
elsie

【输出样例】

2 3
1 1
4 4
2 3

【样例解释】
无论如何,字符串a必然出现在原始列表中第一个,类似的,字符串xzy必然出现在原始列表中的最后一个。
而字符串essiebelsie都有可能位于原始列表的第 2 2 2位或第 3 3 3位,这取决于它们的原始字母顺序。
例如,bessieelsie分别位于 2 , 3 2,3 2,3位,sisbeeilees分别位于 3 , 2 3,2 3,2位。

【分析】


首先设字符串数组 a [ N ] a[N] a[N]存储初始的 N N N个字符串, b [ N ] b[N] b[N]存储每个字符串的最小字典序排列,且 b b b为从小到大有序的, c [ N ] c[N] c[N]存储每个字符串的最大字典序排列,且 c c c也为从小到大有序的。

字符串 a [ i ] a[i] a[i]的最低位置一定是 a [ i ] a[i] a[i]最小字典序排列在 c c c数组中最靠左的且使 c c c仍保持升序的位置 x 1 x_1 x1,即找到第一个大于等于 a [ i ] a[i] a[i]的字符串 c [ x 1 ] c[x_1] c[x1],将 a [ i ] a[i] a[i]插入在这。由于 c c c数组中的字符串是所有字符串的最大字典序,因此 a [ i ] a[i] a[i] c c c中的位置 x 2 x_2 x2一定大于等于 x 1 x_1 x1。因此插入 a [ i ] a[i] a[i]且删除 c [ x 2 ] c[x_2] c[x2] a [ i ] a[i] a[i]的最低位置依旧是 x 1 x_1 x1

字符串 a [ i ] a[i] a[i]的最高位置一定是 a [ i ] a[i] a[i]最大字典序排列在 b b b数组中最靠右的且使 b b b仍保持升序的位置 x 1 x_1 x1,即找到最后一个小于等于 a [ i ] a[i] a[i]的字符串 b [ x 1 ] b[x_1] b[x1],将 a [ i ] a[i] a[i]插入在 b [ x 1 + 1 ] b[x_1+1] b[x1+1]。由于 b b b数组中的字符串是所有字符串的最小字典序,因此 a [ i ] a[i] a[i] b b b中的位置 x 2 x_2 x2一定小于等于 x 1 x_1 x1。因此插入 a [ i ] a[i] a[i]且删除 b [ x 2 ] b[x_2] b[x2] a [ i ] a[i] a[i]的最高位置为 x 1 + 1 − 1 x_1+1-1 x1+11依旧是 x 1 x_1 x1

综上,我们使用 a [ i ] a[i] a[i]的最小字典序在 c c c数组中二分查找出第一个大于等于 a [ i ] a[i] a[i]的位置即为最低位置;使用 a [ i ] a[i] a[i]的最大字典序在 b b b数组中二分查找出最后一个小于等于 a [ i ] a[i] a[i]的位置即为最高位置。


【代码】

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;

const int N = 50010;
string a[N], b[N], c[N];//a为初始字符串数组,b(c)为所有字符串最小(大)值的有序数组
int n;

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        c[i] = b[i] = a[i];
        sort(b[i].begin(), b[i].end());
        sort(c[i].begin(), c[i].end(), greater<char>());
    }
    sort(b + 1, b + 1 + n), sort(c + 1, c + 1 + n);
    for (int i = 1; i <= n; i++)
    {
        sort(a[i].begin(), a[i].end());//在最大值数组中找出a[i]的最小值的位置即为最前位置
        int l = 1, r = n;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (c[mid] >= a[i]) r = mid;
            else l = mid + 1;
        }
        cout << r << ' ';
        reverse(a[i].begin(), a[i].end());在最小值数组中找出a[i]的最大值的位置即为最后位置
        l = 1, r = n;
        while (l < r)
        {
            int mid = l + r + 1 >> 1;
            if (b[mid] <= a[i]) l = mid;
            else r = mid - 1;
        }
        cout << r << endl;
    }
    return 0;
}
举报

相关推荐

0 条评论