题意:题目大意:有n坨豌豆,每坨都有w[i]个,现在要从中选择连续的若干坨,然后用一个能装p个豌豆的背包装豆子,直到剩下的豌豆数量<=p为止,还要求剩下的豌豆数量少于k,问最多能装多少包。-------引自ZeroClock
题解:
1.目标是求(sum[i] - sum[j](i != j)) % p <= k && 使得sum[i] - sum[j]最大
2.变形-----(sum[i] % p - sum[j] % p + p) % p <= k
3.然后我们可以按sum[i] % p,给数组排序。
4.用单调队列分情况讨论解决这个问题了
5.hint:因为存在某堆有0个bean的情况,需要在排序的时候特殊处理
总结:
1.这道题又是看到zeroclock说需要把式子变形之后才知道怎么写的。
2.当没有方向的时候,应该尝试着对公式进行小小的变形,貌似在这种地方栽过好几次跟头了
3.最近依旧学习opencv,几乎把书从头到尾的读了一遍,发现确实应该抓住重点看书,看急需了解的知识,对于不会
的需要延伸的知识,再去有目的的查资料,这样效率更高!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAXN 1000005
int n,p,k;
struct Node
{
ll s;
bool operator < (const Node & a)const{
if(s % p == a.s % p)return s < a.s;
return s % p < a.s % p;
}
}node[MAXN];
ll deque[MAXN];
int main()
{
int _;
for(int kcas = scanf("%d",&_);kcas <= _;kcas++)
{
scanf("%d%d%d",&n,&p,&k);
bool success = false;
for(int i = 1;i <= n;i++)
{
scanf("%I64d",&node[i].s);
if(node[i].s == 0)success = true;
node[i].s += node[i - 1].s;
}
sort(node,node + n + 1);
ll maxn = 0,ans = 0;
int tail = 0,head = 0;
for(int i = 1,j = 0;i <= n;i++)
{
while(tail != head && deque[tail - 1] > node[i - 1].s)
tail--;
deque[tail++] = node[i - 1].s;
while(tail != head && deque[head] % p + k < node[i].s % p)
head++;
if(head != tail)ans = max(ans,node[i].s - deque[head]);
while(j < i && node[j].s % p + p - node[i].s % p <= k)
{
maxn = max(maxn,node[j].s);
j++;
}
ans = max(ans,maxn - node[i].s);
}
if(!ans && !success)printf("Case %d: -1\n",kcas);
else printf("Case %d: %I64d\n",kcas,ans / p);
}
}