1 条题解

  • 0
    @ 2025-8-24 21:45:29

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar WZKQWQ
    还活着

    搬运于2025-08-24 21:45:28,当前版本为作者最后更新于2020-08-04 17:40:24,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这篇题解受大佬NewErAd的启发而出

    其实我就是让大家更好的理解它的思路

    看了记录是第2快的(因为我懒得用快读,第一用了快读快输)

    和第一只差0.05s


    珂爱的分割线

    介绍思想:

    dp[i]表示集合i能最多看几分钟电影,

    转移呼之欲出

    选一个不在集合的点j把它加入

    当j最小的电影开始时间小于dp[i]时

    dp[i |(1 << j)] = max(dp[i |(1 << j)],a[j][#] + d[j]);

    (#是最好的电影开始时间,后面会求)

    不然考虑继承状态:dp[i |(1 << j)] = dp[i];

    当找到一个dp[i] > L时:ans = min(ans,cnt1(i));

    int cnt1(int x)
    {
        int num = 0;
        while (x)
        {
            if (x & 1)
                num++;
            x = x >> 1;
        }
        return num;
    }
    

    这个数1函数不用我说了吧。

    现在我们来看前面的#怎么求

    upper_bound以a[j] + 1, a[j] + a[j][0] + 1, f[i]) - a[j];

    这个函数是求以a[j] + 1开头,以a[j] + a[j][0] + 1结尾

    (这里我用a[j][0]保存一部电影有几场)

    的数组里不大于f[i]的第一个数的下标。

    当它小于1时就不存在这个数。

    伪代码来一波:

    for (int i = 0; i < DP; i++)
        {
            if(f[i] == -1) continue;
            for (int j = 0; j < n; j++)
            {
                if (i & (1 << j))
                    continue;
                int p = upper_bound(a[j] + 1, a[j] + a[j][0] + 1, f[i]) - a[j];
                if (p > 1)
                    f[i | (1 << j)] = max(f[i | (1 << j)], a[j][p - 1] + d[j]);
                else
                    f[i | (1 << j)] = f[i];
            }
            if (f[i] >= m)
                ans = min(ans, cnt1(i));
        }
    

    其他代码呼之欲出,都是细节:

    看在写题解那么辛苦的份上点个赞再走吧

    你们在等的:

    #include <bits/stdc++.h>
    using namespace std;
    int n, m, d[25], a[25][1005], f[1 << 20];
    int cnt1(int x)
    {
        int num = 0;
        while (x)
        {
            if (x & 1)
                num++;
            x = x >> 1;
        }
        return num;
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d", &d[i], &a[i][0]);
            for (int j = 1; j <= a[i][0]; j++)
                scanf("%d", &a[i][j]);
        }
        int DP = 1 << n, ans = 1e9;
        memset(f,-1,sizeof(f));
        f[0] = 0;
        for (int i = 0; i < DP; i++)
        {
            if(f[i] == -1) continue;
            for (int j = 0; j < n; j++)
            {
                if (i & (1 << j))
                    continue;
                int p = upper_bound(a[j] + 1, a[j] + a[j][0] + 1, f[i]) - a[j];
                if (p > 1)
                    f[i | (1 << j)] = max(f[i | (1 << j)], a[j][p - 1] + d[j]);
                else
                    f[i | (1 << j)] = f[i];
            }
            if (f[i] >= m)
                ans = min(ans, cnt1(i));
        }
        if (ans == 1e9)
            printf("-1");
        else
            printf("%d", ans);
        return 0;
    }
    
    • 1

    信息

    ID
    2182
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者