BZOJ2442: [Usaco2011 Open]修剪草坪
阿新 • • 發佈:2017-11-03
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]修剪草坪