链接:http://acm.hdu.edu.cn/showproblem.php?pid=2430
题目大概讲述:给你n堆豆子,按序号排列,现让你任取连续堆豆子,将其装在许多大小为p的袋子里,剩余的豆子不能超过k,问最多能装多少袋?
这道题若是用单调队列做:
你应当找出每个位置,和在其前面的与其坐标差距最大的位置,并且两位置之间的豆子总数%p<=k。
用单调递增队列来做,余数大的堆被排在后面,余数小的堆被排在前面,然后创立一个大小为n的数组。遍历一遍,找到每个位置对应的位置,再用数组保存起来,遍历一遍,求出最大值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef struct Node
{
int mod;
int pos;
}node;
node res[1000010];
__int64 all[1000010];
int mmin[1000010];
node que[1000010];
bool com(node a, node b)
{
if (a.mod != b.mod)
return a.mod < b.mod;
return a.pos < b.pos;
}
int main()
{
int times;
int cl = 0;
scanf("%d", ×);
while (times--)
{
memset(que, 0, sizeof(que));
memset(res, 0, sizeof(res));
memset(all, 0, sizeof(all));
memset(mmin, 0, sizeof(mmin));
int n, p, k;
scanf("%d%d%d", &n, &p, &k);
for (int i = 1; i <= n; i++)
{
scanf("%d", &all[i]);
all[i] += all[i - 1];
res[i].pos = i;
res[i].mod = all[i] % p;
}
sort(res+1, res + n + 1, com);
int tail = 1, head = 0;
__int64 ans = -1;
for (int i = 1; i <= n; i++)
{
if (tail <= head )
mmin[res[i].pos] = que[tail].pos;
else
mmin[res[i].pos] = -1;
while (tail <= head&&res[i].pos<que[head].pos)
head--;
que[++head] = res[i];
while (tail <= head&&(res[i+1].mod - que[tail].mod) > k)
tail++;
}
for (int i = 1; i <= n; i++)
{
if (all[i] % p <= k)
{
if (ans < all[i] / p)
{
ans = all[i] / p;
}
}
else
if (mmin[i] != -1&&mmin[i]<i )
{
if (ans < (all[i] - all[mmin[i]])/p)
ans = (all[i] - all[mmin[i]]) / p;
}
}
printf("Case %d: %I64d\n", ++cl, ans);
}
return 0;
}