哎我還是太菜了,這麼短的** 斷斷續續 調了好久。
看資料範圍 大概就是狀壓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表示...