zoukankan      html  css  js  c++  java
  • 【XDU1144】合并模板

    问题

    Fate 有 n 个 ACM/ICPC 比赛的模板,每个都是一个独立的 PDF 文件。为了便于打印,万神希望将这些模板合并成一个 PDF 文件。万神有一个工具,可以将至多 k 个 PDF 文件合并为 1 个,合并后的文件大小是原来 k 个文件的大小之和。万神发现,这个工具每次运行的时间正比于输出文件的大小。设每输出 1KB 需要 1 单位时间,那么万神至少要多少时间才能合并完所有的文件呢?

    输入格式

    输入文件包含多组数据(最多 100 组),请处理到文件结束。
    每组数据包含 2 行,第 1 行包含两个整数 n、k,用空格分割。
    第二行包含 n 个整数 s1 · · · sn,用空格分割,表示原始的 n 个模板文件的大小(单位为 KB)。
    保证 1 ≤ n ≤ 1000,2 ≤ k ≤ 1000,1 ≤ si ≤ 109。

    输出格式

    对于每组数据输出 1 行,表示合并所有文件需要的最短时间。

    输入样例

    7 4
    1 2 3 4 5 6 7
    3 5
    1 2 3

    输出样例

    38
    6

    样例解释

    对于第一组样例,首先合并前 4 个文件,耗费 10 单位时间。之后把生成的大小 10KB 的文件和后 3 个文件合并,耗费 28 单位时间,共计 38 单位时间。不存在时间更少的合并方案。
    对于第二组样例,可以一次合并所有文件。

    HINT

    对于较大的数据,你可能需要使用 64 位整数。

    代码

    /*
    problem:合并模板
    task: 一次最多合并k个pdf花费代价为合并页数之和,求合并n个页数为si的pdf的最小代价。
    tutorial: 对于每页,参与合并的次数越多,总代价越大,所以每次尽量合并k个最少页数的。
    注意到如果每次合并k个后最后一次只需合并少于k个,那么,让第一次合并少于k个,这样可以花费更少代价将其合并为1个pdf。
    可以每次都排一次序,不过维护两个单调队列也可以,只要排一次序。
    s是未合并的,h是合并过的。
    每次取min(min(s),min(h)),min(s)就是s.top,min(h)就是h.top。
    合并好的插入h队列。每次合并时累加答案。
    */
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define N 1005
    #define ll long long
    using namespace std;
    int n,k,t,p;
    ll s[N],h[N];
    ll solve()
    {
        int top=p+1,htop=0;
        printf("p=%d %d",p,h[0]);
        ll ans=p?h[0]:0;//加上第一次合并的代价,p==0即没有合并过,则h[0]==s[0],ans要=0,而不是h[0]。
        for(int i=1; i<=t; i++)//合并t次
        {
            for(int j=0; j<k; j++)//合并k个
                if(htop==i||s[top]<h[htop]&&top<n)//第i次合并如果前面i-1次合并的已经用过了,就不能再从h里面选了
                    h[i]+=s[top++];
                else
                    h[i]+=h[htop++];
            ans+=h[i];//累加答案
        }
        return ans;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&k))
        {
            memset(h,0,sizeof h);
            for(int i=0; i<n; i++)
                scanf("%lld",&s[i]);
            sort(s,s+n);
            t=(n-1)/(k-1);//每次最大合并减少k-1个pdf,全部合并需要减少n-1张,于是需要t次最大合并(t是向下取整的)
            p=n-1-t*(k-1);//还要一次合并是减少p(p<k-1)张的。
            for(int i=0; i<=p; i++)//合并最小的p+1张
                h[0]+=s[i];
            printf("%lld
    ",solve());
        }
        return 0;
    }

      

  • 相关阅读:
    Balanced Binary Tree
    Convert Sorted List to Binary Search Tree
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Validate Binary Search Tree
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Maximum Depth of Binary Tree
    如何把U盘的两个盘或者多个盘合成一个
    bugku 想蹭网先解开密码
  • 原文地址:https://www.cnblogs.com/flipped/p/5438422.html
Copyright © 2011-2022 走看看