hdu2430Beans(单调队列)

 Mr. Pote's shop sells beans now. He has N bags of beans in his warehouse, and he has numbered them with 1, 2, …, N according to their expired dates. The i-th bag contains Wi units of beans. For selling at retail makes only a little profit, Mr. Pote want to pack beans in small packets with certain size and sell them in packets. Here comes his packing way:
      Suppose the size of the packet is P units. Firstly, Mr. Pote selects some bags (at least one) of beans with consecutive number in his warehouse. Then he takes out the beans from all selected bags, and puts them together on the desktop. To pack the beans, he take P units of beans from desktop and fill in a new packet each time, until the beans left are less than P units. Finally the beans left on the desktop are eaten by a lucky dog.
      Mr. Pote doesn't want the dog eat too many beans, so he prefers to solutions that resulting no more than K units of beans eaten by the dog. Moreover, he also wants to pack as many packets as possible. Could you tell him how many packets he can pack at most without breaking his preference?

Input      On the first line of input, there is a single positive integer T <= 20 specifying the number of test cases to follow.
      Each test case contains two lines.
      There are three integers in the first line, N, P, K as described above. (0 < N, P < 1000001, 0 <= K < P)
      Next follow a line with N integers W1, W2, ..., WN. The i-th integers describes the amount of beans in the bags numbered i. (0 <= Wi < 32768)
      Numbers are separated by spaces.
Output      For each test case you should output a single line containing "Case X: Y" (quotes for clarity) where X is the number of the test case (starting at 1) and Y is the maximum number of packets that Mr. Pote can pack following his way.
      In case there's no solution avoiding the dog eats more than K units of beans, Y should be equal to -1.
Sample Input

3
10 20 10
0 3 1 8 19 39 2 9 1 8
3 100 10
32 34 23
1 5 3
1

Sample Output

Case 1: 4
Case 2: -1
Case 3: 0

题意:

先t组输入,之后输入n、p、k

n:有n袋豆子

p:重新装袋后每袋中豆子的数量

k:狗粮不能超过多少豆子

后边在输入n袋豆子中,每一袋里面豆子的数量

让你从n袋豆子中挑选出来连续的袋子,再将所有豆子重装进p数量的袋子,问最多能装多少袋(在狗粮不超过k的情况下)

 

题解:

详解原文:传送门

首先我们要求选出来连续的袋子,那么肯定要预处理一下前缀和(这里记为sum[i],rem[i]=sum[i]%p)

我们就是再求(sum[i]-sum[j])/p  (i>j)的最大值,要保证(sum[i]-sum[j])%p<=k

当sum[i]>=sum[j]时:

可化简至:sum[i]%p-sum[j]%p<=k  ===>>>   rem[i]-rem[j]<=k

只需要在满足此条件下,找到最大的sum[i]-sum[j]就可以了,而且这一点还可以用单调递增队列来维护,每次取队头来和sum[i]做计算就可以了

 

当sum[i]<sum[j]时

有sum[i]%p-sum[j]%p+p<=k   =====>>>>     rem[i]-rem[j]+p<=k    =====>>>>       rem[i]<=k+(rem[j]-p)

因为rem<p 所以   rem[i]<k

而且(sum[i]-sum[j])<sum[i]

所以我们可以处理一下前缀和sum[i],来取最大的sum[i]/p

 

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=1e5+10;
 7 struct shudui
 8 {
 9     int sum,id,rem;
10 }m[maxn];
11 bool mmp(shudui x,shudui y)
12 {
13     if(x.rem==y.rem)
14         return x.id<y.id;
15     else return x.rem<y.rem;
16 }
17 int que[maxn];
18 int main()
19 {
20     int t,tt=0;
21     scanf("%d",&t);
22     while(t--)
23     {
24         int n,p,k;
25         scanf("%d%d%d",&n,&p,&k);
26         m[0].sum=0;
27         for(int i=1;i<=n;++i)
28         {
29             int q;
30             scanf("%d",&q);
31             m[i].sum=m[i-1].sum+q;
32             m[i].rem=m[i].sum%p;
33             m[i].id=i;
34         }
35         sort(m+1,m+1+n,mmp);
36         int s=1,e=0,ans=0,flag=0;
37         for(int i=1;i<=n;++i)
38         {
39             while(e>=s && m[que[e]].id>m[i].id)
40                 e--;
41             while(e>=s && m[i].rem-m[que[s]].rem>k)
42                 s++;
43             que[++e]=i;
44             if(m[i].rem<=k)
45             ans=max(ans,m[i].sum/p),flag=1;
46             if(e>s && m[i].rem-m[que[s]].rem<=k)
47             ans=max(ans,(m[i].sum-m[que[s]].sum)/p),flag=1;
48         }
49         if(flag)
50         printf("Case %d: %d\n",++tt,ans);
51         else printf("Case %d: -1\n",++tt);
52     }
53     return 0;
54 }
View Code

 

转载于:https://www.cnblogs.com/kongbursi-2292702937/p/11325378.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值