1996. 打乱字母 - 贪心、二分

1996. 打乱字母 - 贪心、二分

1996. 打乱字母

题意

给定\(n\)个字符串,每个字符串的排序可以任意调整,求每个字符串在这种情况下的最大、最小字典序排名。

模型转换

首先我们把字典序当作一个数值,数值越小,排名越靠前。由于可以调整,每个字符串都对应了一个数值变化范围。值得注意的是,这个变化范围本身就有最大值和最小值。

这样,我们就会有\(n\)个这样的范围,虽然每个数都不确定的,但根据我们要求的量——例如最高位置,我们可以很贪心的想到,若要求第\(i\)个字符串的最高位置,不是只要让它取范围里的最小值,让其它字符串取范围里的最大值就好了吗?

感觉非常正确,但还需要进一步的证明。

贪心证明

对于第\(i\)个字符的最高位置而言:

欲证贪心解是最优解,只需证:

  1. \(贪心解 \ge 最优解\)
  2. \(贪心解 \le 最优解\)

对于第一项,我们希望找出最高位置,则\(一般解 \ge 最优解\),而贪心解是一般解的其中一个,故\(贪心解 \ge 最优解\).

对于第二项,我们常用反证法以及调整法,这里使用反证法证明它不成立。

image-20220110114520723

以后看着这张图回忆吧 == ,有点懒 =_=

最小位置同理。

证毕之后我们就可以考虑实现的问题了。

代码实现

要实现的功能有:

  1. 让一个字符串\(i\)取范围里的最小值/最大值
  2. 让其它字符串取范围里的最大值/最小值
  3. 查询经过上述变化后字符串\(i\)的排名

康康数据范围:\(1 \le N \le 50000\),这就要求我们使用$O(n\log n) $以内的算法。

第一项,可以对一个字符串进行排序实现。

第二项,可以在输入的时候额外开两个数组,记录每一项的最大值/最小值。

第三项,根据范围的提示,由于要查询每一个数,所以平均一个数的复杂度是\(O(\log n)\)的,这就提示我们使用二分查找。

这样下来雏形就差不多了,剩下的就是一些细节问题。

代码

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

const int N = 50010;

string a[N], big[N], small[N];
int n;

int main(void){
    cin >> n;
    for (int i = 1; i <= n; i ++ ){
        cin >> a[i];
        big[i] = small[i] = a[i];
        sort(big[i].begin(), big[i].end(), greater<char>() ); // 降序排序,字典序大
        sort(small[i].begin(), small[i].end());
    }

    sort(big + 1, big + n + 1);
    sort(small + 1, small + n + 1);
    
    for (int i = 1; i <= n; i ++ ){
        sort(a[i].begin(), a[i].end());     // 升序,字典序小,排名靠前
        int l = 1, r = n;                   // 此处要在big数组中二分出第一个小于 x 的位置,且靠前,找出 x 的最前排名
        while (l < r){
            int mid = l + r >> 1;
            if (big[mid] >= a[i]) r = mid;  //这种情况mid不需要加一
            else l = mid + 1;
        } 
        cout << l << ' ';
        reverse(a[i].begin(), a[i].end());  // 降序,字典序大,排名靠后
        l = 1, r = n;                       // 此处要在small数组中二分出第一个大于 x 的位置,且靠后,找出 x 的最后排名
        while (l < r){
            int mid = l + r + 1>> 1;
            if (small[mid] <= a[i]) l = mid;
            else r = mid - 1;
        }
        cout << l << endl;
    }
    return 0;
}
posted @ 2022-01-23 11:06  tsrigo  阅读(28)  评论(0编辑  收藏  举报