Time Limit: 3 second
Memory Limit: 2 MB

有n个人排队到r个水龙头去打水,他们装满水桶的时间t1,t2,....tn为整数且各不相等,应如何安排他们的打水顺序才能使他们花费的总时间最少。

Input

输入文件两行
第一行输入打水人数n,水龙头数r。用空格隔开
第二行依次输入n个人的打水时间t1,t2,....tn,用空格隔开(1≤n≤1000)。

Output

输出总共花费的时间。(最后用换行结束)

Sample Input

4 2
2 6 4 5

Sample Output

23

【题解】

样例的取法

2 4 5 6

注意只有两个水龙头

先每个人都等2个单位 ->8

0 2 5 6

再每个人都等两个单位 这下只有3个人等了 -> 6

0 0 3 6

再每人等3个单位 这下只有2个人等了 -> 6

0 0 0 3

最后一个人再等3个单位,->3

总共23个单位.

贪心法,每次装水的时候先让花费时间少的人先装,这样其他所有人都在等,他们等的时间就会比较少,而这个花费时间少的人打完之后,一起等的人就变成N-1个了,剩下的时间可能比较长,但是人数变少了,肯定比n个人一起等时间长的花费时间来得短。先排序,然后用几个变量作为头尾不断减就好。

 

【代码】

#include <cstdio>

const int MAXN = 1000;

int n,r,a[MAXN*10+100],sum = 0,num;

void input_data() //输入数据
{
    for (int i = 1;i <= MAXN*10;i++) //先置0 这可以作为跳出循环的边界
        a[i] = 0;
    scanf("%d %d",&n,&r);
    for (int i = 1;i <= n;i++)
        scanf("%d",&a[i]);
    num = n; //num没用到。
}

void kp(int l,int r) //快排一遍。 从小到大排
{
    int i = l,j = r,m = a[(i+j)/2];
    do
    {
        while (a[i] < m) i++;
        while (m < a[j]) j--;
        if (i <= j)
            {
                int t = a[i];a[i] = a[j];a[j] = t;
                i++;j--;
            }
    }
    while (i <= j);
    if (l < j) kp(l,j);
    if (i < r) kp(i,r);
}

void get_ans()
{

    int i = 1,j = 1 + r -1; //这是头尾指针 要注意超过n变成n 这里的头尾指的是能在有限的水龙头上打水的人。
    if (j > n) j = n;
    while (a[i] > 0) //如果还有东西可以减 那么。。
        {
            int d = a[i]; //先获取要花费的时间(取最短时间)
            for (int k = i;k <= j;k++) //水龙头上的人每个人都减少一些时间
                a[k]-=d;
            for (int k = i;k <= n;k++) //每个在等的人都增加时间。
                sum+=d;
            while (a[i] == 0 && i<=n ) i++; //找下一个在等的人。
            j = i + r -1;
            if (j > n) j = n;
        }
}

void output_ans()
{
    printf("%d\n",sum);
}

int main()
{
    input_data();
    kp(1,n);
    get_ans();
    output_ans();
    return 0;
}