1. 程式人生 > >洛谷題解【愛與愁的心痛】

洛谷題解【愛與愁的心痛】

name 左右 ret 得到 貪心 clu 思路 sin 表示

題目傳送門

思路

本題難度本為入門難度,因為他的數據很小,用O(n2)的暴力算法就可以AC,但是,作為一個對於認為自己水題過多而感到羞愧的OIer,我決定用O(n)的算法來做這道題.

我不打算用前綴和(其實就是不會),用前綴和也可以做出O(n)的時間復雜度,但是很復雜,而且常數因子還比我接下來要介紹的算法的常數因子大,所以,我自認為我的這個算法是洛谷全站最好的(我翻了題解).

思想:貪心&動態規劃

如果a[n]<a[m+1],那麽a[n]~a[m]區間的和一定小於a[n+1]~a[m+1]區間的和.

而a[n+1]~a[m+1]區間的和減a[n]~a[m]區間的和就等於a[m+1]-a[n].

則用b[m+1]表示a[m+1]-a[n],那麽a[n+2]~a[m+2]區間的和減a[n]~a[m]區間的和就等於a[m+1]-a[n]+a[m+2]-a[n+1]也就是b[m+1]+a[m+2]-a[n+1].而他的值又可以用b[m+2]表示

所以得到狀態轉移方程為:b[m+2]=b[m+1]+a[m+2]-a[n+1].

另外,若a[1]~a[m]就是最小的或n=m,則程序會出現錯誤,需要特判:

if(b[no]>0||n==m)//特判
        no=m;

剩下的就很簡單了,直接上代碼.

Code

#include <iostream>
#include 
<queue> using namespace std; long long n,m,gkmin=9999999999999999,ans,no;//我就是喜歡把gkmin設的大一點,你咬我啊 long long a[3002]; long long b[3002]; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; } for(int i=1;i<=n-m;i++) { b[i
+m]=b[i+m-1]+a[i+m]-a[i];//狀態轉移 if(gkmin>b[i+m]) gkmin=b[i+m],no=i+m; } if(b[no]>0||n==m)//特判 no=m; for(int i=no;i>no-m;i--) ans+=a[i]; cout<<ans; return 0; }

後記

為了裝逼敲一個高性能代碼,我足足提交了20次左右,才AC.好吧,我承認是我自己在折磨我自己QAQ.

洛谷題解【愛與愁的心痛】