18 8 14 考試總結 dp專場

2022-05-20 02:03:47 字數 4829 閱讀 7286

最長上公升子串行(lis)

給出乙個數列,找出其中最長上公升子串行的長度。上公升子串行中前乙個數嚴格小於後乙個數。

【輸入格式】

第一行乙個數n,表示數的個數。

第二行n個數,第i個數表示ai。

【輸出格式】

乙個整數,表示最長上公升子串行的長度。

這道題還是比較簡單了 資料範圍要求的是nlog的演算法

一些dalao寫的是老李講過的在前面二分

我比較蒟蒻 我自己yy...

就弄了乙個值域線段樹 因為數是1e9大小 所以在離散化一下就可以了

**

#include using

namespace

std;

const

int n = 100000 + 5

;int n,m,a[n],f[4 *n],b[n];

int query(int o,int l,int r,int l,int

r) void update(int

o) void modify(int o,int l,int r,int pos,int

val)

int mid = (l + r) >> 1

;

if(pos <= mid) modify(2 *o,l,mid,pos,val);

else modify(2 * o + 1,mid + 1

,r,pos,val);

update(o);

}int

main( )

sort(b + 1,b + n + 1

); m = unique(b + 1,b + n + 1) - b - 1

;

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

printf("%d

",f[1

]);

return0;

}

隔離村莊(isolate)有n個村莊,通過n-1條雙向路連通。jyb同學財大氣粗,想要買其中的恰好k個村莊。為了做一些秘密的事情,

他想要通過破壞原來的路,在保證自己的k個村莊相互連通的情況下,把這k個村莊與其他村莊隔離開。

請問他應該買哪k個村莊,最少破壞多少條路呢?

【輸入格式】

第一行兩個數n, k,表示村莊的個數和jyb想要買的村莊個數。

接下來n-1行,每一行兩個數u, v。表示村莊u與v相連。

【輸出格式】

乙個整數,表示最少破壞路的條數。

我思維真的太垃圾了 一開始我還想的網路流搞乙個最小割 就是因為這個垃圾資料範圍是n,k <= 150

什麼列舉連通塊然後跑最小割什麼的嘔

然後就有了更騷的貪心演算法... 就是每個點加入塊中會產生新的需要割的點和減去原來相連的玩意兒

我就貪心弄出來最小的費用 然鵝我並不會定義優先佇列... 鹹魚攤

正解是乙個樹上dp

有兩種做法

1.我們可以發現每個連通塊他需要割掉的邊的條數是(sigma d) - (2 * k - 2) sigma d是所有點的度數和

後面那一坨是乙個常數 然後就轉化成了求最小度數的連通塊 就把每個點的權值搞成他的度數就可以了

就跑乙個樹上揹包就可以了

2.同樣是樹上揹包 定三維 dp[u][k][0/1]表示以u為根的子樹保留k個 保留的當中有沒有u的最小切割方案

然後就是對轉移進行討論 乙個是直接從一棵子樹轉移而來 還可能從不止一棵子樹轉移而來

不止一棵的時候一定要從dp[son][p][1]轉移過來 這樣才能保證它是乙個連通塊 很多細節多注意一下就可以了

**

#include using

namespace

std;

const

int n = 155

;int tot,head[n],nex[2 * n],tov[2 * n],size[n],dp[n][n][2

],k,n;

void add(int u,int

v) void dfs(int u,int

fa)

dp[u][

1][1] =flag;

for(int i = head[u];i;i =nex[i])

}int s[155],ma = min(size[u],k) - 1

; memset(s,

0x3f,sizeof

(s));

s[0] =flag;

for(int i = head[u];i;i =nex[i]) }}

for(int i = 1;i <= ma + 1;i ++) dp[u][i][1] = min(dp[u][i][1],s[i - 1

]);}

intmain( )

memset(dp,

0x3f,sizeof

(dp));

dfs(

1,1);

printf("%d

",min(dp[1][k][1],dp[1][k][0

]));

}

多公尺諾骨牌(domino)有乙個r * c的矩形,和一些1*2的多公尺諾骨牌。jyb想用這些骨牌剛好填滿這個矩形,

使得沒有位置是空出來的,多公尺諾骨牌也沒有重疊。

請問jyb有多少種方法剛好填滿這個矩形呢?一種可能的填法如下圖:

設定矩形是有方向的,旋轉之後相同和相互對稱的填法應當計算為不同的填法。

【輸入格式】

第一行兩個數r,c。表示矩陣的列數和行數

【輸出格式】

乙個整數,表示填法總數。

很經典的輪廓線dp 做過好幾遍了 就是細心 然後特判最後一列就可以了

做的時候我tm空間開小了掉了40分 昨天又是開大了 難受

**

#include typedef 

long

long

ll;using

namespace

std;

intr,c;

ll dp[

13][13][1

<< 13

];int

main( )

else

if((s & 1) == 0

)

if(s & 1

) }

else

if((s & 1) == 0

)

if(s & 1

) }}}

}}printf(

"%i64d

",dp[r][c][(1

<< c) - 1

]);

return0;

}

湊硬幣(coin)jyb想給他的女朋友買一塊很貴的巧克力,jyb有n個硬幣,第i個硬幣的價值為ci元,

巧克力的**為k。jyb想用一些硬幣湊出恰好k元為他的女朋友買一塊巧克力。

看著他的硬幣,他想到了乙個問題,假設他不給女朋友巧克力,而是給她k元的硬幣,

她用這恰好k元的硬幣可以湊出哪些價值呢?他想不出來,於是請你幫他解答這個問題。

更準確地說,jyb想要知道所有的價值x,在jyb的硬幣中能夠找出乙個恰好k元的子集s,

使得存在s的子集s2,s2硬幣價值的和是x。顯然0和k都是符合條件的x。

【輸入格式】

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

第二行n個正整數,表示硬幣的價值ci。

【輸出格式】

第一行乙個整數n,表示能湊出的價值的個數。

第二行n個不同的整數,從小到大排序,列舉題意描述的能湊出的值。

做的時候我打的搜尋狗了40 搜完了之後的dp其實和正解的思路很像了 但是就是沒想到啊

思維太蒟了...  dp[k][x]表示子集和為k的子集能不能湊出值為x的數 

就或一下就好了 小心超界

**

#include using

namespace

std;

const

int n = 2500 + 10

;int

n,k,a[n];

bool

dp[n][n];

intmain( )

for(int s = a[i];s <= j;s ++) }}

int ans = 0

;

for(int i = 0;i <= k;i ++) ans +=dp[k][i];

printf(

"%d\n

",ans);

for(int i = 0;i <= k;i ++) if(dp[k][i]) printf("

%d "

,i);

}

最可惜的就是第三題...  還要繼續加油 爭取衝到前面去...!!

衝鴨.....!!!!!!!!!!!!!!!!!!!w

2 17狀壓dp有關考試總結

考試內容分析 t1音量調節 給定初始值 在不超過最大值且不小於0的前提下,將初值加上或減去每個讀入的數,使結果最大,若定會超過最大值或小於0,則輸出 1 分析 感覺是dp 求最大值很有dp那味。但是感覺 總體最大值無法通過區域性最大值匯出 在推狀態轉移方程的時候無法射出狀態或者表示出很好的方程 耗費...

ACM學習感悟 暴力專場E 暴力dp

problem description 小晴天 我有乙個數列!小晴天 我還要有很多很多的數列!於是小晴天就把這個數列的所有連續子數列寫出來。然後小晴天把每個連續子數列中的最大的數寫出來。那麼,有多少個比k大呢?input 多組資料,首先是乙個正整數t t 100 表示資料的組數 對於每組資料,首先是...

數學考試dp

來自 先是read 函式,用於快速讀入,比cin快,比printf快 int read ch getchar while ch 0 ch 9 return x f 呼叫函式的時候定義乙個新變數 比如輸入乙個t,表示測試次數 int t t read 接下來是看題幹,兩個不連續的區間 區間長度為k i...