📜  期末考试 | Google Kickstart 2021 D 轮

📅  最后修改于: 2022-05-13 01:56:09.133000             🧑  作者: Mango

期末考试 | Google Kickstart 2021 D 轮

是时候进行算法和数据结构的期末考试了!

Edsger 准备了N组问题。每组由难度递增的问题组成;第 i 个集合可以用两个整数 Ai 和 Bi (Ai≤Bi) 来描述,表示这个集合包含困难 Ai, Ai+1…, Bi。在所有集合的所有问题中,保证没有两个问题具有相同的难度。

本学期 Edsger 必须测试M个学生。他想用他的一组中的一个问题来测试每个学生。没有两个学生可以得到完全相同的问题,所以当 Edsger 测试一个有问题的学生时,他不能再使用这个问题了。通过无数的讲座、练习和项目,Edsger 已经衡量了学生 j 的技能水平 Sj,并希望给那个学生一个难度 Sj 的问题。不幸的是,这并不总是可能的,因为 Edsger 可能没有准备好这个难度的问题,或者他可能已经提前向其他学生提出了这个问题。因此,Edsger 将为第 j 个学生选择一个难度为 Pj 的问题,其方式为 |Pj−Sj|是最小的,并且在第 j 个学生之前没有给任何学生一个难度 Pj 的问题。在平局的情况下,Edsger 将始终选择更容易的问题。请注意,为第 j 个学生选择的问题可能会影响为以后测试的所有学生选择的问题,因此您必须按照学生在输入中出现的顺序来处理他们。

由于跟踪所有问题可能相当复杂,您能否帮助 Edsger 并确定他应该为所有学生提供哪些问题?

或者

给定一个包含N对的数组questionRange ,其起始值和结束值作为难度级别的范围,一个大小为M的数组arr表示每个学生可以尝试的难度级别。任务是 issueRange中的唯一整数X分配给数组arr中的每个整数,使得| arr[i] - X |被最小化。如果两个最接近arr[i]的值相等,则必须选择一个较小的难度值。 X值必须按学生的顺序分配给学生,因为不能将相同的X值分配给多个学生。打印分配给每个学生的X值。

例子:

方法:给定问题可以通过以下步骤解决:

  • 使用映射将范围的开始存储为键,将范围的结束存储为值
  • 迭代数组并为其中的每个元素在地图中找到它的lower_bound
  • 可能有两种情况: Lower_bound将返回指向等于arr[i]的键或刚好大于arr[i]的键的迭代器
    • 假设由lower_bound提供的迭代器 be itpre是它之前的迭代器(当it = mp.begin()pre将等于
    • pre.first<=arr[i]<=pre.secondit.first<=arr[i]<=it.second都是真的。 arr[i]将位于此范围的前向部分或后向部分
    • 每次将值分配给arr[i]之前的范围都会从地图中删除,并添加一个新范围,如图所示
    • 添加两个新范围或添加一个新范围,如下图所示:

范围中仅存在一个元素,因此将其删除并且不添加新范围

arr[i] 等于任一范围

先前的范围被删除,地图中添加了两个新范围

下面是上述方法的实现:

C++
// C++ implementation for the above approach
 
#include 
 
using namespace std;
 
void solve(long long int N, long long int M,
           vector >
               problemRange,
           vector arr)
{
 
    // Store the problem range in a map
    map mp;
 
    for (long long int i = 0; i < N; i++) {
        long long int a, b;
        a = problemRange[i].first;
        b = problemRange[i].second;
        mp[a] = b;
    }
 
    vector ans(M);
 
    for (long long int i = 0; i < M; i++) {
        auto it = mp.lower_bound(arr[i]);
        auto pre = it;
        if (it != mp.begin())
            pre--;
 
        // If answer lies in a valid range
        if (pre->first <= arr[i]
            && arr[i] <= pre->second) {
            ans[i] = arr[i];
            long long int st = pre->first,
                          end = pre->second;
            mp.erase(pre);
            long long int left = arr[i] - 1,
                          right = arr[i] + 1;
            if (st <= left) {
                mp[st] = left;
            }
            if (end >= right) {
                mp[right] = end;
            }
        }
 
        // If answer is not in a valid range
        else {
            long long int op1 = pre->second,
                          op2 = it->first;
            if (abs(arr[i] - op1) <= abs(arr[i] - op2)) {
                ans[i] = op1;
                long long int st = pre->first,
                              end = op1 - 1;
                mp.erase(pre);
                if (st <= end)
                    mp[st] = end;
            }
            else {
                ans[i] = op2;
                long long int st = it->first + 1,
                              end = it->second;
                mp.erase(it);
                if (st <= end)
                    mp[st] = end;
            }
        }
    }
    for (auto it : ans)
        cout << it << " ";
    cout << endl;
}
 
// Driver code
int main()
{
    long long int N, M;
    N = 5;
    M = 4;
 
    // Student difficulty level
    vector arr = { 14, 24, 24, 4 };
 
    vector >
        problemRange = { { 1, 2 },
                         { 6, 7 },
                         { 9, 12 },
                         { 24, 24 },
                         { 41, 50 } };
    solve(N, M, problemRange, arr);
    return 0;
}


输出
12 24 11 2 

时间复杂度: MLog(N)
辅助空间: O(N)