洛谷1484 種樹

2022-05-11 11:45:12 字數 1955 閱讀 8530

cyrcyr今天在種樹,他在一條直線上挖了n個坑。這n個坑都可以種樹,但為了保證每一棵樹都有充足的養料,cyrcyr不會在相鄰的兩個坑中種 樹。而且由於cyrcyr的樹種不夠,他至多會種k棵樹。假設cyrcyr有某種神能力,能預知自己在某個坑種樹的獲利會是多少(可能為負),請你幫助他 計算出他的最大獲利。

輸入格式:

第一行,兩個正整數n,k。

第二行,n個正整數,第i個數表示在直線上從左往右數第i個坑種樹的獲利。

輸出格式:

輸出1個數,表示cyrcyr種樹的最大獲利。

輸入樣例#1:

6 3 

100 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 #include6

using

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...