BZOJ 3591 最長上公升子串行

2021-08-10 08:55:31 字數 1236 閱讀 9742

哎我還是太菜了,這麼短的** 斷斷續續 調了好久。

看資料範圍 大概就是狀壓dp

題目名字是【最長上公升子串行】 可以猜測是拿跑li

s 的單調棧搞搞。

那麼可以設計乙個狀態f[

a][b

] 表示已選集合

a ,其中

b是當前單調棧裡的元素,顯然棧裡的元素公升序排列,不用額外加一維狀態表示棧中元素的排列。顯然這可以優化成3n

的狀態表示。

轉移大概就是列舉

a 補集中的每個元素

x加到單調棧中某個位置,兩邊的元素保留。由於題目已經給出乙個必選的li

s(記為c)

,並且dp

做的最後的時候所有元素都會被加進來,所以我們只要在dp

過程中排除掉非法情況就可以了,這裡會產生非法情況當且僅當

x 屬於

c且加入

x 的時候跳過了另乙個屬於

c的元素,也就是在

c 中,

x的前乙個元素未被加入已選集合

a 。可以預處理出g[

i][j

]表示已選集合

i 加入元素

j是否合法。

還有乙個不知道有多大用 的常數優化。就是限制一下

b 的大小使其不超過

c的大小。

#include 

using namespace std;

const int n=15;

int n,m,s,t,pre[n],bit[1<],pow3[n],g[1<][n],d[1<][n],f[14348908],h[1

for(pow3[0]=i=1;is=(1

>1]+(i&1);

for(i=0;i<=s;++i)for(j=0;jfor(i=0;i<=s;++i)for(j=0;j

if(!((1if(bit[((1<<(j+1))-1)&i]

for(k=1<<(j+1);k<=i&&!(k&i);k<<=1);

d[i][j]=1f[0]=1;

for(i=0;i<=s;++i)for(k=0;k

for(j=i;;j=(j-1)&i)

}int ans=0;

for(i=1;i<=s;++i)if(bit[i]<=m)ans+=f[h[s]+h[i]];

printf("%d",ans);

return 0;

}

BZOJ3591 最長上公升子串行

考慮我們做最長上公升子的過程,維護乙個單調棧,每次加入乙個元素,替換掉最前面乙個比他大的數 我們可以dp這個加入元素的過程,用乙個3進製的狀態表示每個數在不在佇列裡且在不在棧裡,可以用o n22n o n 22n 預處理對於棧中的每個狀態,加入乙個新的數之後的狀態 然後做乙個o n3n o n 3n...

BZOJ 3591 最長上公升子串行

題目鏈結 題意 給定 k kk 個數,求所有長度為 n nn 且最長上公升子串行的排列為給定的 k kk 個數的方案數。n 15 n 15 n 1 5首先想到可以用狀壓解決排列的順序問題,而僅通過 0,1 0,10,1 無法表達出最長上公升子串行的長度,而再開一維進行表示也無法進行有效轉移。那麼考慮...

BZOJ3591 最長上公升子串行 狀壓DP

description 給出1 n的乙個排列的乙個最長上公升子串行,求原排列可能的種類數。sample input53 1 3 4 sample output 11挺好的dp題。我們先考慮普通lis,我們維護乙個序列,每一次盡量去替換序列中的值。對於這個,可以用乙個三進製維護,0表示未進佇列,1表示...