链接: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; }