分享一道排序题 现在有5000个数,每个数在 [0,99] ,都是整数,要求排序, 时间复杂度 O(n)

介绍了一种针对5000个位于[0,99]区间内整数的排序方法,通过构建特定的数据结构实现O(n)的时间复杂度,适用于需要高效排序的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:现在有5000个数, 每个数在 [0,99] ,并且每个数都是整数,现在要求排序从大到小或者从小到大,

          要求时间复杂度为 O(n);


解决方法:

[[0],[1],[2],[3],[4],[5],[6],[7],[8],[9]......[98],[99]]

定义这个一个结构,依次插入相应位置即可;

<think>好的,我现在得解决这个排队接水的问目是说有n个人在m个水龙头前排队,每个人接水的时间是Ti,我们需要找到一种排队顺序,使得所有人的总等待时间最小。输出这个最小的总等待时间。那该怎么做呢? 首先,我得理解什么是总等待时间。比如,假设有一个水龙头,当第一个人接水的时候,后面的人都要等待他的时间。假设三个人接水时间为t1、t2、t3。顺序是t1、t2、t3的话,总等待时间是t1(第二个人等待) + (t1 + t2)(第三个人等待)。总共有t1*2 + t2*1。也就是每个人的等待时间是前面所有人接水时间的总和。总等待时间就是每个人的等待时间的总和。 那么当有多个水龙头的时候,如何安排才能使总等待时间最小呢?这个时候应该用贪心算法。具体来说,应该是让每个水龙头上的任务尽可能的短,这样后面的人等待的时间总和才会小。 比如,如果有多个水龙头,我们可以将接水时间短的人先安排,这样可以减少后面人的等待时间。但是,具体如何分配呢? 假设每个水龙头处理一个队列,我们需要将每个任务分配给当前总时间最小的那个水龙头。例如,初始时所有水龙头的可用时间都是0。然后,每次选择当前可用时间最小的那个水龙头,把下一个任务分配给它。这样,每个任务的等待时间就是该水龙头当前的总时间。然后将该水龙头的总时间加上当前任务的接水时间。总等待时间就是所有任务的等待时间的总和。 比如,假设m=3,任务按时间排序后的组是1,12,33,55,56,99,99,234,812,1000。按从小到大排序。然后我们分配这些任务到三个水龙头。 初始三个水龙头的可用时间都是0。分配第一个任务(1)到第一个水龙头,总等待时间加0(因为当前可用时间是0,任务本身的接水时间不算等待时间?或者可能目中的等待时间是否包括自己的时间?需要仔细看问描述。) 目中总等待时间指的是每个人的等待时间之和。例如,每个人接水的时候需要等待的时间是他开始接水前已经等待的时间总和。比如,在水龙头队列中,第一个人不需要等待,第二个人要等第一个人的时间,第三个人等前两个人的时间总和。这个时候,每个水龙头的队列中的任务的等待时间之和是该队列每个元素的接水时间乘以后面元素的量之和。 比如,假设一个水龙头的队列是a1, a2, a3。那么总等待时间是a1*(2)(a2和a3等待a1的时间) +a2*1(a3等待a2的时间)。所以总等待时间是a1*(n-1) +a2*(n-2-1)?或者更一般地说,每个元素ai的贡献是ai乘以该队列中在它之后的任务的量之和。例如,如果队列中有k个任务,那么每个第i个任务的贡献是 ai*(k - i -1 +1 -1)?或者说,队列中的第一个人的等待时间是0,第二个人的等待时间是a1,第三个人的等待时间是a1+a2。总共有三个人的话,总等待时间是 a1 (第二个人) + (a1+a2)(第三个人)= a1*2 + a2*1。所以,总等待时间等于队列中每个元素的接水时间乘以(队列中后面元素的个数)的总和。 所以,对于每个水龙头的队列,总等待时间是该队列中每个任务的接水时间乘以该任务之后的任务量之和的总和。那么,为了使总等待时间最小,我们需要将每个水龙头的队列中的任务按接水时间从小到大排列。因为这样,较大的接水时间会被乘以较小的乘(后面任务少),而较小的接水时间会被乘以较大的乘。这样整体总和才会最小。这其实是贪心算法的经典问,类似于任务调度中的最短处理时间优先(SPT)规则。 因此,正确的策略应该是:将所有人的接水时间从小到大排序,然后依次分配到各个水龙头队列中。例如,如果有m个水龙头,那么每个水龙头依次被分配排序后的任务。比如,第一个任务给水龙头1,第二个给水龙头2,...第m个给水龙头m,第m+1个给水龙头1,依此类推。这样每个水龙头的队列中的任务都是按时间从小到大排列的。这样,每个水龙头的队列中的总等待时间就是最优的。将所有水龙头的总等待时间相加,就是整体的总等待时间。 这样,总的问的解决步骤应该是: 1. 将所有的接水时间Ti进行升序排序。 2. 将这n个任务分配到m个队列中,每个队列按轮转的方式分配,即第一个任务给队列0,第二个给队列1,...第m个给队列m-1,第m+1个给队列0,依此类推。 3. 每个队列的总等待时间可以通过计算每个元素的接水时间乘以其后面的元素个数之和。 4. 所有队列的总等待时间之和即为答案。 那如何高效地计算每个队列的总等待时间呢? 比如,假设队列中的任务为t0, t1, ..., tk-1。那么总等待时间是 t0*(k-1) + t1*(k-2) + ... + tk-2*1。或者,可以看成每个ti的贡献是 ti*(该队列中在它之后的任务)。例如,对于队列中的第i个元素(0-based),它后面有 (k-1 -i)个元素。因此,总贡献是 ti*(k-1 -i) 的总和。 例如,队列有元素排序后的组为 [a, b, c, d]。总共有4个元素。那么总等待时间是 a*3 + b*2 + c*1 + d*0?但d的贡献是0?因为d之后没有人需要等待。那总等待时间应该是每个元素后面的元素目之和乘以该元素的时间。 是的。所以总等待时间等于每个元素的ti乘以其在队列中的位置之后的元素目之和。 那如何高效计算这个总和呢?假设队列的长度是k,那么对于每个元素ti,它的贡献是 ti*(k - pos -1),其中pos是它在队列中的位置(从0开始)。比如,第一个元素pos=0,贡献ti*(k-1 -0) = ti*(k-1)。 那可以先将队列中的元素排序后,计算每个元素对应的乘,然后相乘求和。 现在,如何分配任务到各个队列呢?假设将排序后的组依次分配给m个队列,每个队列尽可能平均分配。例如,如果有n=10,m=3,那么队列0有4个任务,队列1和2各3个?或者按照轮转方式,每个队列得到ceil(n/m)或floor(n/m)的任务? 比如,对于n=10,m=3,排序后的组是1,12,33,55,56,99,99,234,812,1000。按照轮转分配的话,每个队列得到的元素是: 队列0: 1,55,99,1000 → 4个元素? 或者,可能分配方式是: 顺序分配,比如第1个元素给队列0,第二个给队列1,第三个给队列2,第四个给队列0,第五个给队列1,第六个给队列2,第七个给队列0,依此类推。例如: 队列0:1(第1个)、55(第4个)、99(第7个)、812(第10个?假设原排序后是升序,原输入样例中的排序可能不同?比如原样例的输入是56 12 1 99 1000 234 33 55 99 812。排序后的顺序应该是按升序排列后的组。原输入样例的输出是457,所以需要验证这个思路是否正确。) 不管怎样,分配的方式应该是将排序后的组按顺序依次分配给各个队列,每个队列按照顺序添加元素。比如,排序后的组是升序的,那么第0到m-1个元素分别分配到各个队列的第一个位置。然后接下来的每个元素分配到当前总长度最短的队列?或者轮转的方式? 或者,正确的分配方式是将排序后的组按从小到大顺序,依次分配到各个队列中,每个队列的分配顺序是轮转的。例如,第一个元素给队列0,第二个给队列1,第三个给队列2,第四个给队列0,第五个给队列1,依此类推。这样每个队列中的元素目尽可能平均。这可以使得每个队列中的元素目差不超过1。 例如,当n=10,m=3时,队列的目分布可能是4,3,3。这样,每个队列中的元素目最多相差1。那么,每个队列的总等待时间之和就是各队列内的总和之和。 那这样,对于每个队列来说,它的元素目是k,那么总等待时间的计算方法是: sum_{i=0 to k-1} ti * (k - i -1) 那如何高效计算这个总和呢? 假设队列的元素已经按升序排列,那么可以遍历每个元素,乘以后面的元素目,累加即可。 例如,队列的元素是t0, t1, ..., tk-1,按升序排列。那么总和是: sum_{i=0}^{k-1} t_i * (k-1 -i) 现在,整个问的解法步骤如下: 1. 输入n和m,以及n个接水时间。 2. 将接水时间按升序排序。 3. 将排序后的组分配到m个队列中,轮转分配,即第i个元素分配到i%m的队列中。 4. 对于每个队列,计算该队列的总等待时间。 5. 将所有队列的总等待时间相加,得到最终结果。 那如何实现这个过程呢? 例如,在C++中,可以用一个数组或vector的vector来存储每个队列的元素。但是当n是1e5的时候,这样的存储方式可能效率不够,或者内存占用较大。有没有更高效的方法? 或者,可以计算每个队列中的元素目,然后直接根据排序后的组的位置来计算出每个队列的总等待时间,而不需要实际存储每个队列的元素。 例如,假设排序后的组是sorted_t。然后将每个队列的元素目是k = ceil(n/m)或者类似的。或者,每个队列的元素目是 floor(n/m)或 floor(n/m)+1,具体取决于n和m的关系。例如,当n=10,m=3时,每个队列的元素目是4,3,3。因为10 = 3*3 +1,所以前1个队列有3+1=4元素,其他两个3个。 但是这可能不是轮转分配的情况。轮转分配的话,每个队列的元素目可能相差最多1。例如,轮转分配的话,第0队列的元素目是 ceil(n/m),如果n%m !=0的话。例如,n=10,m=3,10%3=1,所以前1个队列有4个元素,后面的每个队列有3个。或者,轮转分配的话,每个队列的元素目是n/m的商,余部分的队列各加一个元素。例如,余是r,则前r个队列每个加一个元素。比如n=10,m=3,商是3,余1。所以前1个队列有3+1=4,剩下的两个队列各3个。这正好是轮转分配后的结果吗? 例如,对于排序后的组按轮转方式分配,队列0将得到索引0,3,6,9的元素?或者可能我之前的例子中的分配方式可能不同? 或者,轮转分配的方式是每个元素i被分配到i%m的队列中。那么,排序后的组的元素按0到n-1的顺序,每个元素i分配到i%m的队列。例如,当n=10,m=3时,每个元素的i%m为0,1,2,0,1,2,0,1,2,0。这样队列0得到第0,3,6,9这四个元素,队列1得到1,4,7,队列2得到2,5,8。这样,队列0的元素目是4,队列1和2各3个。这样,每个队列中的元素目是尽可能平均的。 在这种情况下,每个队列的元素目为k_j = (n + m - j -1)/m ,其中j是队列的索引?或者更简单地说,每个队列的元素目是 (n // m) + (j < (n % m) ? 1 :0 )。例如,当n=10,m=3时,余是1。前1个队列(j=0)的元素目是3+1=4,其他两个队列是3。这样,每个队列的元素目取决于是否在余范围内。 所以,在这种情况下,每个队列的元素目是: 队列j的元素目 = base + (j < remainder ? 1 :0 ) 其中,base = n / m, remainder =n %m。 例如,n=10,m=3,base=3, remainder=1。所以队列0的目是3+1=4,队列1和2目是3+0=3。 所以,每个队列中的元素目可以这样计算。然后,每个队列中的元素是排序后的组中的哪些元素? 比如,对于队列j来说,它的元素目是k_j = base + (j < remainder ?1 :0)。那么,每个元素在排序后的组中的索引为: 队列j的第i个元素的索引是 j + i*m。例如: 当j=0,队列目是4: i从0到3: 元素索引是0, 0+1*3=3, 0+2*3=6, 0+3*3=9。对吗?这似乎和轮转分配不同。例如,原轮转分配的方式是按i%m的余,即第0元素分配到队列0,第1元素队列1,第2元素队列2,第3元素队列0,等等。所以,队列0的元素是索引0,3,6,9。这对应的顺序是每隔m=3个元素选一个。这种情况下,每个队列中的元素目等于k_j,而元素的位置是相隔m的步长。例如,对于队列j,其元素的索引为 j, j+m, j+2m, ...,直到超过n-1。 这样的话,每个队列中的元素目是k_j= (n -j +m-1)/m。或者说,每个队列的元素目等于 ceil( (n-j)/m )。这似乎比较复杂。 或者,不管余如何,每个队列j的元素目是k_j= base + (j < remainder ?1:0 )。而每个队列的元素是排序后的组中的连续块吗?比如,前r个队列各分配一个额外元素,每个队列的元素目为base+1。比如,当n=10,m=3时,r=1。队列0的目是4,队列1和2目是3。排序后的组中的前4个元素给队列0?然后接下来的3给队列1,然后3给队列2? 或者,可能我之前的方法不正确。例如,轮转分配和分组分配是不同的。轮转分配是将元素依次分配给各个队列,而分组分配是将元素分为连续的块。 例如,当采用轮转分配时,队列中的元素可能不是连续的块,而是每隔m个元素取一个。例如,当排序后的组是升序的,轮转分配会导致每个队列中的元素是每隔m步取一个。这可能使得每个队列中的元素在排序后的组中相对分散,而各个队列中的元素目相差不超过1。这似乎对总等待时间的计算不会有影响,因为每个队列内部都是按升序排列的? 或者,是否轮转分配和分组分配的结果不同? 比如,假设排序后的组是1,2,3,4,5,6,m=2。轮转分配的话,队列0得到1,3,5,队列1得到2,4,6。每个队列目是3。分组分配的话,前三个元素给队列0,后三个给队列1。总等待时间是否一样? 对于轮转分配的情况,队列0的总等待时间:1*(3-1-0-1)?或者队列0的元素是1、3、5。那么总等待时间是1*(2) +3*(1) +5*(0) =2+3=5。队列1的元素是2、4、6。总等待是2*2 +4*1=4+4=8。总和是13。 如果是分组分配,队列0的元素是1、2、3。总等待是1*2 +2*1=2+2=4。队列1的元素是4、5、6。总等待是4*2+5*1=8+5=13。总和是17。比轮转分配的结果更大。这说明分组分配的方式不如轮转分配的方式优。这说明,轮转分配的方式更好,即让每个队列的元素尽可能交替地取较小的和较大的元素,这样每个队列内部的时间总和会更小。 所以,正确的分配方式应该是轮转分配,即每个队列中的元素目相差不超过1,并且元素在排序后的组中按轮转方式分配,这样每个队列中的元素尽可能分散,使得每个队列的总等待时间更小。 那如何实现轮转分配,并计算总等待时间? 例如,对于每个队列j(0 ≤j <m),它的元素目是k_j= base + (j < remainder ?1:0),其中 base= n/m, remainder= n%m。每个元素i在排序后的组中的索引是i。队列j的元素是排序后的组中所有i%m ==j的i的元素。 例如,当i从0到n-1,每个i%m等于j的元素被分配到队列j。这样,队列j的元素目等于k_j= (n +m -j -1)/m 的整数除法。或者更简单地说,每个队列j的元素目等于(n -j +m-1)/m。例如,当n=10,m=3时,队列0的元素目是(10-0 +3-1)/3=12/3=4。队列1的目是(10-1+3-1)/3=11/3=3.666,取整数部分3。队列2的目是(10-2+3-1)/3=10/3=3.333,取3。这样总共有4+3+3=10个元素。 那每个队列j中的元素目是k_j= ceil( (n-j)/m )。或者,可以用以下方式计算每个队列j的元素目: k_j = (n -j +m-1)/m 例如,当n=10,m=3: 队列0: (10-0+2)/3=12/3=4 →4个元素。 队列1: (10-1+2)/3=11/3=3.666 →取整数除法,得到3。 队列2: (10-2+2)/3=10/3=3.333 →整数除法得到3. 这样总共有4+3+3=10。这正确。 这样,每个队列中的元素目是正确的。 现在,对于每个队列j中的元素目k_j,如何计算它的总等待时间? 队列j中的元素是排序后的组中索引为j, j+m, j+2m, ...的元素。例如,队列0的元素是0,3,6,9,队列1的是1,4,7,队列2的是2,5,8。 每个队列中的元素在排序后的组中已经按升序排列,因为整个数组是排序后的。因此,队列中的元素是按升序排列的。例如,假设排序后的组是1,12,33,55,56,99,99,234,812,1000。队列0的元素是索引0(1)、3(55)、6(99)、9(1000)。队列1的元素是1(12)、4(56)、7(234)。队列2的元素是2(33)、5(99)、8(812)。 那么,队列0的等待时间计算: 每个元素的乘是(队列元素目 - pos -1)。 队列0的k_j=4: 元素顺序是1,55,99,1000。它们的索引在队列中的pos是0,1,2,3。对应的乘是3-0-1=2?或者队列的元素目是4,每个元素的乘应该是(4- pos -1)=3 - pos。例如,pos=0,乘3-0=3?或者 pos=0的元素后面有三个元素(pos 1,2,3),所以乘3。这样,总贡献是1*3 +55*2 +99*1 +1000*0 =3 +110 +99 =212?或者原中的样例输出是457。所以需要再仔细看样例输入。 原输入样例的输出是457。那假设原的正确解法是否是这样的? 原输入样例的输入是: 10 3 56 12 1 99 1000 234 33 55 99 812 排序后的组应该是按升序排列后的: 1,12,33,55,56,99,99,234,812,1000. 然后按轮转分配: 队列0的元素是索引0(1)、3(55)、6(99)、9(1000)。队列0的总等待时间为: 1的贡献是3(后面有三个元素)×1 =3×1=3。 55的贡献是后面两个元素,所以2×55=110. 99的贡献是1×99=99. 1000的贡献是0. 总和是3+110+99=212. 队列1的元素是索引1(12)、4(56)、7(234): 元素目是3。 第一个元素12,乘2(后面两个元素)→12×2=24. 第二个元素56,乘1 →56×1=56. 第三个元素234,乘0 →0. 总和是24+56=80. 队列2的元素是索引2(33)、5(99)、8(812): 元素目是3. 33的乘2 →33×2=66. 99的乘1 →99×1=99. 812的乘0 →0. 总和是66+99=165. 总等待时间是212+80+165=457,与样例输出一致。这说明这个方法是正确的。 所以,正确的解法是: 将排序后的组按轮转方式分配给各个队列,每个队列中的元素目由轮转后的结果决定,每个队列内的元素按升序排列,计算每个队列中的总等待时间,然后将所有队列的总等待时间相加。 所以,步骤总结: 1. 输入n和m,以及组t。 2. 将t排序为升序。 3. 初始化总等待时间为0. 4. 对于每个队列j从0到m-1: a. 计算该队列的元素目k_j = (n -j + m -1) / m →使用整数除法。或者更简单地说,k_j等于ceil((n-j)/m)。或者用C++中的表达式:(n - j + m -1)/m. b. 遍历该队列的元素i(i从j开始,步长m,直到i <n). c. 对于每个元素,其在队列中的位置是 pos = (i -j)/m →因为i = j + pos*m →pos从0到k_j-1. d. 该元素的乘(k_j - pos -1) →因为后面有k_j - pos -1个元素。 e. 将该元素t[i]乘以乘,加到总等待时间中。 例如,队列j的元素是i =j, j+m, j+2m,...,直到i >=n。每个元素的pos是0,1,2,...,k_j-1. 这样,总等待时间的计算可以通过遍历每个队列j,然后对于每个队列中的元素i,计算其贡献。 这样的算法的时间复杂度是O(n log n)(因为排序的时间)加上O(n)(遍历所有元素计算贡献)。因为n可以是1e5,所以这样的复杂度是可行的。 现在,如何编写这个算法的C++代码? 代码的大体步骤: - 读取n和m。 - 读取t组,并排序。 - 计算总等待时间sum=0. - 对于每个j in 0..m-1: - 计算该队列的元素目k_j = (n - j + m -1) / m →例如,当n=10,j=0,得到 (10-0 +3-1)/3=12/3=4. - 然后,对于每个元素i in j, j+m, j+2m,... <n: - pos = (i -j)/m →例如,i=3时,j=0,m=3 →(3-0)/3=1. - multiplier = (k_j - pos -1). - sum += t[i] * multiplier. 例如,在样例中: j=0的队列: k_j=(10-0 +3-1)/3=12/3=4. i遍历0,3,6,9. 对于i=0: pos=(0-0)/3=0 →multiplier=4-0-1=3 →sum +=1*3. i=3: pos=(3-0)/3=1 →multiplier=4-1-1=2 →sum +=55*2=110. i=6: pos=6/3=2 →multiplier=4-2-1=1 →sum +=99*1=99. i=9: pos=(9)/3=3 →multiplier=4-3-1=0 →sum +=1000*0=0. 总sum此时3+110+99=212. 然后j=1: k_j=(10-1 +3-1)/3= (11)/3=3. i=1,4,7. i=1: pos=(1-1)/3=0 →multiplier=3-0-1=2 →12*2=24. i=4: pos=(4-1)/3=3/3=1 →multiplier=3-1-1=1 →56*1=56. i=7: pos=(7-1)/3=6/3=2 →multiplier=3-2-1=0 →234*0=0. sum +=24+56=80 →总sum变为292. j=2: k_j=(10-2 +3-1)/3= (10)/3=3. i=2,5,8. i=2: pos=(2-2)/3=0 →multiplier=3-0-1=2 →33*2=66. i=5: pos=(5-2)/3=1 →multiplier=3-1-1=1 →99*1=99. i=8: pos=(8-2)/3=6/3=2 →multiplier=3-2-1=0 →812*0=0. sum +=66+99=165 →总sum=212+80+165=457. 这样,代码正确。 现在,如何实现这个逻辑? 代码的大致结构: #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n, m; cin >> n >> m; vector<int> t(n); for (int i = 0; i < n; ++i) { cin >> t[i]; } sort(t.begin(), t.end()); long long sum = 0; for (int j = 0; j < m; ++j) { int k_j = (n - j + m - 1) / m; // 计算队列j的元素目 for (int i = j; i < n; i += m) { int pos = (i - j) / m; // 当前元素在队列中的位置 int multiplier = k_j - pos - 1; sum += (long long)t[i] * multiplier; } } cout << sum << endl; return 0; } 这样就能得到正确的结果吗? 测试样例: 输入: 10 3 56 12 1 99 1000 234 33 55 99 812 排序后的组是:1,12,33,55,56,99,99,234,812,1000. 队列0的元素是0,3,6,9 →值1,55,99,1000。k_j=4. 每个元素的multiplier: i=0 →pos=0 →multiplier=4-0-1=3 →1*3=3. i=3 →pos=1 →4-1-1=2 →55*2=110. i=6 →pos=2 →4-2-1=1 →99*1=99. i=9 →pos=3 →4-3-1=0 →1000*0=0. 总和3+110+99=212. 队列1的元素是1,4,7 →12,56,234. k_j=3. pos 0 →3-0-1=2 →12*2=24. pos1 →3-1-1=1 →56*1=56. pos2 →3-2-1=0 →234*0=0. 总和24+56=80. 队列2的元素是2,5,8 →33,99,812. k_j=3. pos0 →3-0-1=2 →33*2=66. pos1 →3-1-1=1 →99*1=99. pos2 →3-2-1=0 →812*0=0. 总和66+99=165. 总和212+80+165=457。正确。 所以,代码是正确的。 那问中的n和m可以达到1e5,而这样的算法时间复杂度是O(n log n +n)吗?是的。排序是O(n log n),然后后面的循环是O(n)每个元素被处理一次)。这在1e5的规模下是可行的。 例如,当n=1e5,排序的时间是O(n log n),大约是1e5 * 17 ≈1.7e6 operations。循环部分是O(n)。所以,总体上是可以通过的。 综上,正确的解法是将接水时间排序后,按轮转方式分配到各个水龙头队列,并计算每个元素在其队列中的位置对应的乘,累加得到总等待时间。</think>为了使总等待时间最小,应先将所有人按接水时间升序排列,然后将他们轮流分配到各水龙头队列中。每个队列的总等待时间由各元素的接水时间乘以其后面元素的量之和决定。以下是实现方法: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n, m; cin >> n >> m; vector<int> t(n); for (int i = 0; i < n; ++i) cin >> t[i]; sort(t.begin(), t.end()); long long total = 0; for (int j = 0; j < m; ++j) { int cnt = (n - j + m - 1) / m; // 队列j的元素个数 for (int i = j; i < n; i += m) { int pos = (i - j) / m; // 当前元素在队列中的位置 int weight = cnt - pos - 1; // 计算乘 total += (long long)t[i] * weight; } } cout << total << endl; return 0; } ``` **解释:** 1. **排序接水时间**:将接水时间从小到大排序,确保优先处理短任务。 2. **轮转分配队列**:将排序后的任务依次分配给每个水龙头队列,保证各队列任务尽可能均衡。 3. **计算等待时间**:对于每个队列中的元素,其等待时间为自身接水时间乘以后续元素量,累加所有元素的贡献得到总等待时间。 这种方法通过贪心策略确保短任务优先处理,并利用轮转分配保证队列负载均衡,从而最小化总等待时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值