1 条题解

  • 0
    @ 2025-4-7 22:08:09

    题目解析

    题意分析

    题目描述了一个DVDDVD图书馆的管理问题。我们需要处理一系列DVDDVD请求,目标是在处理完所有请求后,使DVDDVD的插入次数最少。具体规则如下: 有kkDVDDVD驱动器,每个驱动器同一时间只能存放一张DVDDVD。 当请求的DVDDVD已经在某个驱动器中时,无需任何操作。 如果请求的DVDDVD不在任何驱动器中: 如果有空闲的驱动器,直接将DVDDVD插入。 如果没有空闲的驱动器,需要选择一个驱动器中的DVDDVD替换为当前请求的DVDDVD,此时插入次数加11。 我们需要提前知道整个请求序列,并按照顺序处理请求,目标是使总插入次数最小。

    解题思路

    这是一个典型的缓存替换问题,类似于操作系统中的页面置换算法。最优策略是贪心算法中的**最远将来使用(FarthestinFutureFarthest in Future)**策略,即在需要替换时,选择当前缓存中未来最晚被请求的DVDDVD进行替换。

    具体步骤如下: 初始化一个集合SS表示当前驱动器中的DVDDVD集合,初始为空。 遍历请求序列,对于每个请求xix_i: 如果xix_i已经在SS中,直接跳过。 如果xix_i不在SS中: 如果S<k|S| < k,将xix_i插入SS,插入次数加11。 如果S=k|S| = k,需要选择一个DVDDVD替换: 遍历SS中的每个DVDDVD,找到在后续请求中最晚出现(或不再出现)的那个DVDDVD,将其替换为xix_i,插入次数加11。 3. 最终输出总插入次数。

    复杂度分析

    • 对于每个测试用例,需要遍历nn个请求。
    • 对于每个需要替换的请求,需要检查kk个驱动器中的DVDDVD,并在剩余请求中查找其下一次出现的位置。
    • 最坏情况下,每次替换需要O(kn)O(k \cdot n)时间。
    • 总复杂度为O(mn2k)O(m \cdot n^2 \cdot k),由于k10k \leq 10n100n \leq 100,完全可接受。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    
    const int inf = 0x7fffffff;
    int n, m, ans, op[105], pos[1000005];
    bool exist[1000005];
    int drive[15], temp[15];
    //n为DVD drives数量
    //m为操作数
    
    int find(int opr) {
        int res = -1, opaa;
        for(int i = 1; i <= n; i++) {
            if(pos[op[drive[i]]] < opr)
                temp[i] = inf;
            else {
                for(int j = opr + 1; j <= m; j++) {
                    if(op[drive[i]] == op[j]) {
                        temp[i] = j;
                        break;
                    }
                }
            }
        }
        for(int i = 1; i <= n; i++) {
            if(res < temp[i]) {
                res = temp[i];
                opaa = i;
                if(res == inf)
                    break;
            }
        }
        return opaa;
    }
    
    void solve(int opr, int k) { //opr为操作数, k为正在使用的DVD drives编号
        if(opr > m)
            return;
        if(k > n) {
            if(exist[op[opr]])
                solve(opr + 1, k);
            else {
                ans++;
                int opaa = find(opr);
                exist[op[drive[opaa]]] = false;
                exist[op[opr]] = true;
                drive[opaa] = opr;
                solve(opr + 1, k);
            }
        }
        else {
            if(exist[op[opr]])
                solve(opr + 1, k);
            else {
                exist[op[opr]] = true;
                ans++;
                drive[k] = opr;
                solve(opr + 1, k + 1);
            }
        }
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        while(t--) {
            // 手动初始化 exist 数组
            for (int i = 0; i < 1000005; ++i) {
                exist[i] = false;
            }
            // 手动初始化 drive 数组
            for (int i = 0; i < 15; ++i) {
                drive[i] = 0;
            }
            // 手动初始化 temp 数组
            for (int i = 0; i < 15; ++i) {
                temp[i] = 0;
            }
            // 手动初始化 pos 数组
            for (int i = 0; i < 1000005; ++i) {
                pos[i] = 0;
            }
            // 手动初始化 op 数组
            for (int i = 0; i < 105; ++i) {
                op[i] = 0;
            }
    
            ans = 0;
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= m; i++) {
                scanf("%d", &op[i]);
                pos[op[i]] = max(pos[op[i]], i);
            }
            solve(1, 1);
            printf("%d\n", ans);
        }
        return 0;
    }
    
    • 1

    信息

    ID
    1698
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者