複習動規(3)

2022-03-30 07:42:56 字數 3501 閱讀 3479

繼續複習動規。

第一道,[scoi2010]**交易。看起來限制多,其實就是紙老虎。

可設f[i][j]指第i天擁有j張**所賺的最大錢數,所以f[i][j]可為負,所以初值設為-inf。

四種情況:1.什麼都不買,f[i][j]=max

2.第一次買,f[i][j]=max(0<=j<=asi)

3.之後的買,f[i][j]=max-j*api(j-asi

<=k4.賣,f[i][j]=max-j*bpi(ji)

前面兩種直接o(n2),後面兩種用單調佇列優化,第三種從前往後,第四種從後往前,到這裡就不難寫了。

第一道,[scoi2014]方伯伯的玉公尺田。

首先得發現乙個性質,每次修改的區間的右端點一定是最後乙個點,證明如下:

對於這個區間外的左邊的玉公尺,其最長不下降子串行會增大或不變。

而對於右邊的玉公尺,其最長不下降子串行會減小或不變。故要減小右邊的玉公尺數,當然為0最好。證明畢。

設f[i][j]指當前這個玉公尺被拔高後的高度為i且這個玉公尺被j個拔高區間覆蓋的最長不下降子串行長度。

可得:f[i][j]=max+1(k<=i,l<=j)。單做要o(n4),但是字首取最大值我們可以想到樹狀陣列。

於是定義乙個二維樹狀陣列(就是我**裡的f陣列),優化後的時間複雜度為o(n2*logn*logn);

這題想到性質很重要,陣列的定義也很難想到(i am vegetable),再多寫點同型別的題吧。

記得j要倒著列舉避免重複計算,**的具體實現如下:

#include#define lowbit(i) (i&(-i))

using

namespace

std;

const

int n=1e4+1e3;

int n,k,ans,d[n],f[5600][510

];int max(int x,int y)

intrd()

int query(int x,int

y)void change(int x,int y,int

ss)int

main()

printf(

"%d\n

",ans);

return0;

}

[scoi2014]方伯伯的玉公尺田

第二道,[balticoi 2017] toll。很有意思的題。

題目給出了(b/k)=1+(a/k)(括號為下取整號)。所以我們從這個方面去思考。

在思考了幾個世紀後,我們發現(i/k)相同的有很多個i,將這些i當做一整塊,於是n個地點就被分為ceil(n/k)個塊。

然後又可以發現a->b恰好是乙個塊中的點到後面的乙個塊中的點,於是定義f[i]為i到終點的最短路,就可以用矩陣來轉移狀態。

| disx->a    disx->b    disx->c |         | f[a] |       | f[x] |

| disy->a    disy->b    disy->c |    *   | f[b] |   =   | f[y] |

| disz->a    disz->b    disz->c |         | f[c] |       | f[z] |    (這裡的*不是乘法,是新定義的運算c[i][j]=max)

然後想到了什麼?沒錯,就是我們的動態dp。接下來就很簡單了,把dis存下來放到線段樹里,每次查詢「l的塊~r的塊」的矩陣連乘。

又因為f[終點]=0而其他的f為無窮大,所以答案就是矩陣中的某個值。(由l,r決定哪行哪列)。

最後記得判斷-1。**的具體實現如下:

#includeusing

namespace

std;

const

int n=5e4+1e3,m=7e8;

intk,n,m,q,t;

int min(int x,int y)

struct

num inline num

operator*(num b)

}d[n],f[n*4

];int

rd()

void build(int x,int l,int

r)

int mid=(l+r)>>1

; build(x

<<1

,l,mid);

build(x

<<1|1,mid+1

,r);

f[x]=f[x<<1]*f[x<<1|1];}

num query(

int x,int l,int r,int l,int

r)int main()

build(

1,1,t-1

);

while(q--)

return0;

}

[balticoi 2017] toll

第一道,花園。

由m<=5很容易想起狀壓dp,於是設f[i][j]為當前做到第i盆花且最後m盆花的狀態為j的方案數。

這個定義非常快樂,然後我們快樂地轉移。那麼怎麼處理環形呢?

我們只需要每次給一種狀態j的f[m][j]賦值為1,並做到f[n+m][j],將答案累加即可。

再就快樂地提交,然後快樂地wa(不是。

發現n有1015,考慮快速冪。f的轉移可以用鄰接矩陣代替,因此需要矩陣快速冪。

到這裡應該就沒問題了,上**:

#include#define ll long long

using

namespace

std;

const

int n=1e5+1e4,p=1e9+7

;int m,k,ans,tot,f[41],g[41

]; ll n;

struct

num}b,c;

ll rd()

void dfs(int x,int s,int

d) dfs(x+1,s<<1

,d);

dfs(x+1,s<<1|1,d+1);}

num chen(num a,num b)

int main()

while

(n)

for(int i=1;i<=tot;i++)

ans=(ans+c.p[i][i])%p;

printf(

"%d\n

",ans);

return0;

}

花園最後做了道小水題[eer2]諤運算,對每個數字進行討論就行了。行吧就這樣,明天再說。拜拜。

複習動規(1)

今天是7月13號,現在打算衝國銀。從現在到國賽前,每天會複習或學習知識點。今天是複習動態規劃。第一道,noi2001 炮兵陣地。很明顯也很好寫的狀壓dp。dp i j k 是第i行狀態為j,第i 1行狀態為k的方案數,再列舉一重狀態即可。挺經典。第二道,sdoi2009 bill的挑戰。定義的陣列稍...

Employment Planning 動規小練

employment planning 原題鏈結 對於當前月份所需人數,和僱傭最大所需人數之間的情況進行討論。由於解雇金額和僱傭金額的存在,會存在一次性僱傭更多的人以減少解雇金額的情況,所以要討論到所需最大人數。include include include include include incl...

每日演算法 動規高頻題 3

1 target 目標位置 10000 啊那個r僅僅是轉向還有剎車的意思,並不一樣要後開乙個位置,俺就是看著結果莫名其妙的。能夠直接到達的位置是2n 1這種型別的位置,如果無法到達就有兩種清空。1.開過了,得倒回來,這種情況比較簡單,只需加上開到過了的那個位置的運算元 n 開回來的次數 2n 1 x...