繼續複習動規。
第一道,[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))[scoi2014]方伯伯的玉公尺田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;
}
第二道,[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[balticoi 2017] tollnamespace
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;
}
第一道,花園。
由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花園最後做了道小水題[eer2]諤運算,對每個數字進行討論就行了。行吧就這樣,明天再說。拜拜。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;
}
複習動規(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...