1. 程式人生 > >BZOJ2442: [Usaco2011 Open]修剪草坪

BZOJ2442: [Usaco2011 Open]修剪草坪

scanf min lis 一行 ans while 哪些 problem logs

【傳送門: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; }

BZOJ2442: [Usaco2011 Open]修剪草坪