博客
关于我
【luogu P6033】合并果子 加强版
阅读量:325 次
发布时间:2019-03-04

本文共 2681 字,大约阅读时间需要 8 分钟。

合并果子 加强版

题目链接:(待补充)

题目大意:

有一堆东西,每次你可以选两个东西,用它们大小的和的代价把它们合并,得到一个它们大小和的东西。目标是将所有东西合并成一个东西所要的最小代价。

普通的解法中,使用优先队列(堆)的时间复杂度是 O(n log n),但在数据量较大的情况下,这种方法无法通过时间限制。因此,我们需要一种更高效的算法。

思路:

  • 首先,我们需要明确普通解法的思路:使用优先队列(堆)来维护当前处理的最小两个数,从而合并得到最小代价。

  • 但由于数据量较大,普通的 O(n log n) 时间复杂度方法无法通过时间限制。因此,我们需要寻找更高效的方法。

  • 我们可以采用以下思路:首先对数据进行桶排(Bucket Sort),这可以在 O(n) 时间内完成数据的排序。对于大数据量,甚至可以使用基数排序(Frequency Sort)。

  • 接下来,我们需要维护一个队列(Queue)来存储生成的新数。每次合并两个最小的数,生成一个新的数,并将这个新数插入队列中。

  • 新生成的数一定比原来的数大,因此我们可以每次从队列中取出两个最小的数进行合并,直到队列中只剩下一个数为止。

  • 这种方法可以在 O(n) 时间内完成,因为每次合并都减少了一个数,最终需要 n-1 次合并操作。

  • 代码示例:

    手动队列版:

    #include 
    #include
    #define ll long longusing namespace std;int n;ll ans = 0;ll x, y, xx, yy, box[100001];ll q[10000001], p[10000001];ll t, tt;int read() { int re = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') { re = re * 10 + c - '0'; c = getchar(); } return re;}int main() { n = read(); for (int i = 1; i <= n; i++) { x = 1ll * read(); box[x]++; } for (int i = 1; i <= 100000; i++) { for (int j = 1; j <= box[i]; j++) { q[++q[0]] = i; } } while (p[0] + q[0] - t - tt > 1) { x = q[t + 1]; xx = q[t + 2]; y = p[tt + 1]; yy = p[tt + 2]; if (xx < y && t + 2 <= q[0] || (tt + 1 > p[0])) y = xx, t += 2; else if (yy < x && tt + 2 <= p[0] || (t + 1 > q[0])) x = yy, tt += 2; else t++, tt++; ans += x + y; p[++p[0]] = x + y; if (p[0] + q[0] - t - tt <= 1) { break; } } printf("%lld", ans); return 0;}

    自带队列版:

    #include 
    #include
    #define ll long longusing namespace std;int n;ll ans = 0;ll x, y, xx, yy;queue
    q, p;int read() { int re = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') { re = re * 10 + c - '0'; c = getchar(); } return re;}int main() { n = read(); for (int i = 1; i <= n; i++) { x = 1ll * read(); x++; } for (int i = 1; i <= 200000; i++) { for (int j = 1; j <= box[i]; j++) { q.push(i); } } while (1) { if (q.empty() && p.empty()) break; ll min1 = q.front(); q.pop(); if (p.empty()) { if (q.empty()) break; ll min2 = p.front(); p.pop(); if (p.empty()) break; } if (min1 < min2) { x = min1; y = min2; } else { x = min2; y = min1; } ans += x + y; p.push(x + y); } printf("%lld", ans); return 0;}

    注:上述代码可能存在错误,具体请根据实际需求进行调试和优化。

    转载地址:http://ehvh.baihongyu.com/

    你可能感兴趣的文章
    ntelliJ IDEA 报错:找不到包或者找不到符号
    查看>>
    NTFS文件权限管理实战
    查看>>
    ntko web firefox跨浏览器插件_深度比较:2019年6个最好的跨浏览器测试工具
    查看>>
    ntko文件存取错误_苹果推送 macOS 10.15.4:iCloud 云盘文件夹共享终于来了
    查看>>
    ntp server 用法小结
    查看>>
    ntpdate 通过外网同步时间
    查看>>
    ntpdate同步配置文件调整详解
    查看>>
    NTPD使用/etc/ntp.conf配置时钟同步详解
    查看>>
    NTP及Chrony时间同步服务设置
    查看>>
    NTP服务器
    查看>>
    NTP配置
    查看>>
    NUC1077 Humble Numbers【数学计算+打表】
    查看>>
    NuGet Gallery 开源项目快速入门指南
    查看>>
    NuGet(微软.NET开发平台的软件包管理工具)在VisualStudio中的安装的使用
    查看>>
    nuget.org 无法加载源 https://api.nuget.org/v3/index.json 的服务索引
    查看>>
    Nuget~管理自己的包包
    查看>>
    NuGet学习笔记001---了解使用NuGet给net快速获取引用
    查看>>
    nullnullHuge Pages
    查看>>
    NullPointerException Cannot invoke setSkipOutputConversion(boolean) because functionToInvoke is null
    查看>>
    null可以转换成任意非基本类型(int/short/long/float/boolean/byte/double/char以外)
    查看>>