cyrcyr今天在種樹,他在一條直線上挖了n個坑。這n個坑都可以種樹,但為了保證每一棵樹都有充足的養料,cyrcyr不會在相鄰的兩個坑中種 樹。而且由於cyrcyr的樹種不夠,他至多會種k棵樹。假設cyrcyr有某種神能力,能預知自己在某個坑種樹的獲利會是多少(可能為負),請你幫助他 計算出他的最大獲利。
輸入格式:
第一行,兩個正整數n,k。
第二行,n個正整數,第i個數表示在直線上從左往右數第i個坑種樹的獲利。
輸出格式:
輸出1個數,表示cyrcyr種樹的最大獲利。
輸入樣例#1:
6 3100 1 -1 100 1 -1
輸出樣例#1:
200
對於20%的資料,n<=20。
對於50%的資料,n<=6000。
對於100%的資料,n<=500000,k<=n/2,在乙個地方種樹獲利的絕對值在1000000以內。
很容易想到動規思路:f[i][j]表示種到第i棵樹且種了j棵的最大獲利,則f[i][j]=max(f[i-1][j],f[i-2][j-1]+a[i]),注意邊界、初始化即可。
但是,對於本題n<=300000的資料規模,動規顯然不足以通過本題
如果k=1時最優解為a[i],那麼我們便可以把a[i-1]和a[i+1]進行合併,
因為它們要麼同時被選,要麼同時落選(證明不難,請自行解決)。
而且,我們還注意到:當選了a[i-1]和a[i+1]時,獲利便增加了a[i-1]+a[i+1]-a[i]。
所以當a[i]被選時,我們就可以 刪去a[i-1]和a[i+1],並把a[i]改成a[i-1]+a[i+1]-a[i],重新找最大的。 每次找的都是最大的數,我們便可以使用堆進行操作
刪除用鍊錶
1 #include2 #include3 #include4 #include5 #include6using
namespace
std;
7structzt8
;12int l[600001],r[600001
];13
bool vis[600001
];14
intn,m;
15long
long a[600001
];16
bool
operator
<(const zt &a,const zt &b)
1720 priority_queueq;
21int
main()
22 34 l[1]=0;r[n]=n+1;35
long
long ans=0;36
int num=n;
37while (m--)
3846
if (t.v<0) break
; 47 ans+=t.v;
48 vis[t.id]=1
;49 vis[l[t.id]]=1;vis[r[t.id]]=1
;50 num++;
51 l[num]=l[l[t.id]];r[l[num]]=num;
52 r[num]=r[r[t.id]];l[r[num]]=num;
53 a[num]=a[l[t.id]]+a[r[t.id]]-a[t.id];
54q.push((zt));55}
56 cout<57 }
洛谷 P1484 種樹
本題說每選乙個坑,它的左右兩個坑都不能選了,可是我們沒有辦法確定我們選某個坑一定是最優解,怎麼辦呢?我們設定乙個反悔機制,每當選乙個坑,就新設定乙個點,使這個點的值為這個坑兩邊的和減去當前坑的差.為什麼這樣做是對的呢?感性想一下,如果再後面的選坑過程中,我們選到了這個新設定的點,說明我們選上文的那個...
洛谷 P1484 種樹 思維 堆
洛谷 p1484 種樹 思維 堆 很容易想到用乙個大根堆來儲存每個位置的獲利,但我們不能每次都取出根元素後,將其兩邊的元素標記位不可選擇,因為這個根元素兩邊的元素之和很可能大於這個根元素,這時我們選擇的就不是根元素,而是兩邊的元素,所以我們要有乙個反悔選擇的機會,我們在選擇根元素的時候,在總獲利中加...
洛谷P1484種樹(堆 較難貪心)
題意很清晰很好懂,做起來就難了。資料範圍小的化可搜尋可dp,but資料這麼大是不可能的了,較難貪心 a i 或左加右只選乙個最大的 堆 每次取出最大的 1 include 2 include 3 include 4 using namespace std 5 typedef long long ll...