BZOJ2442: [Usaco2011 Open]修剪草坪
【传送门:BZOJ2442】
简要题意:
约翰让他的奶牛来修建草坪。他有N 头奶牛,第i 头奶牛的工作能力为Ai。编号相近的奶牛很 熟悉,如果同时让K + 1 头编号连在一起的奶牛工作,她们就会密谋罢工。请问,约翰应该让哪些奶 牛同时工作,使得它们的能力之和最大,而且不会罢工。
输入格式:
• 第一行:两个整数N 和K,1 ≤ K ≤ N ≤ 10^5
• 第二行到N + 1 行:第i + 1 行有一个整数Ai,1 ≤ Ai ≤ 10^9
输出格式:
• 单个整数,表示在所有不会罢工的奶牛组合之中,最大的能力之和
样例输入:
5 2
1
2
3
4
5
样例输出:
12
样例解释:
除了第三头以外的所有奶牛都工作,总能力 为1 + 2 + 4 + 5 = 12
题解:
一开始想到用DP,以为可以AC,结果发现数据范围惊人,想到用单调队列或者斜率优化来搞搞
想了好久没想出来,后来发现可以转化为每k+1个数就要选一个数,求最小和的经典单调队列例题,求出最小和之后,用所有数的和减去最小和就是这道题的正解了
尴尬的是,被long long硬是卡了十几分钟......
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; typedef long long LL; struct node { LL x;int p; node() { x=0LL; } }list[110000]; LL a[110000],f[110000]; int main() { int n,k; scanf("%d%d",&n,&k);k++; LL s=0; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); s+=a[i]; } if(n<=k-1) { printf("%lld\n",s); return 0; } int head=1,tail=1; LL ans=99999999999; for(int i=1;i<=n;i++) { while(head<=tail&&i-list[head].p>k) head++; f[i]=list[head].x+a[i]; while(head<=tail&&f[i]<=list[tail].x) tail--; tail++;list[tail].x=f[i];list[tail].p=i; } for(int i=n-k+1;i<=n;i++) ans=min(ans,f[i]); printf("%lld\n",s-ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚