UOJ 394 NOI2018 氣泡排序

2022-03-31 14:43:57 字數 1554 閱讀 3632

首先我們發現乙個數不能既被往左換又被往右換。也就是說不能有任何乙個數左邊有比他大的,又被有比他小的。

也就是最長下降子串行長度不超過 2 。

所以我們一定可以找到 2 個上公升序列包含所有的數。

於是容易想到 $o(n^2)$ 的 dp:

$dp_$ 表示加入了 $i$ 個數,最大值為 $j$ 的情況下,填完的方案數。

那麼,如果下乙個數小於 $i$ ,那肯定是填小於 $j$ 的第乙個,否則就是填乙個比 $j$ 更大的值。

我們把這個東西看做括號序列,填乙個比 $j$ 大的值就相當於加入若干個左括號,然後再加入乙個右括號;填乙個比 $j$ 小的數字就相當於加入乙個右括號。

這個東西的方案數可以用類似於卡特蘭數的公式 $c_i = \binom - \binom $ 的推導方法來得到。

這個請自行搜尋,懶得畫圖了。

#pragma gcc optimize("ofast","inline")

#include #define clr(x) memset(x,0,sizeof (x))

#define for(i,a,b) for (int i=a;i<=b;i++)

#define fod(i,b,a) for (int i=b;i>=a;i--)

#define pb push_back

#define mp make_pair

#define fi first

#define se second

#define _seed_ ('c'+'l'+'y'+'a'+'k'+'i'+'o'+'i')

#define outval(x) printf(#x" = %d\n",x)

#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")

#define outtag(x) puts("----------"#x"----------")

#define outarr(a,l,r) printf(#a"[%d...%d] = ",l,r);\

for(_v2,l,r)printf("%d ",a[_v2]);puts("");

using namespace std;

typedef long long ll;

ll read()

const int n=1200005,mod=998244353;

void add(int &x,int y)

void del(int &x,int y)

int pow(int x,int y)

int n;

int fac[n],inv[n];

void prework()

int c(int n,int m)

int p[n];

int q[n],head,tail;

int pos,vis[n];

int calc(int x,int y)

void main()

vis[p[i]]=1;

} cout<}int main()

NOI2018 氣泡排序

noi2018 氣泡排序 題解性質 模型轉化 首先,乙個排列是 好 的,當且僅當 每個數,要麼是字首最大值,要麼是字尾最小值。討論i和pi的關係即可證明 也就是,排列不能存在 3的下降子串行!換句話說,假設之前填了i個數,最大值是mx,那麼第i 1個數,要麼是剩下數的最小值,要麼是比mx大的數。字典...

NOI2018 氣泡排序

題面 吐槽 好像發的pdf題面的冒泡是掛掛的,還好我還會氣泡排序 逃 具體思路 首先發現當這個序列的最長下降序列長度大於2時,一定不符合要求 那麼我們可以想出乙個 o n 2 的dp f i,j 表示前 i 個數,設其中最大的數為 mx 後面的數中有 j 個數比 mx 小的方案數 然後發現 f i,...

BZOJ 5416 Noi2018 氣泡排序

bzoj 5416 noi2018 氣泡排序 dp 組合數 樹狀陣列 好題。合法的排列的交換次數剛好是交換次數的下界,也就是說不能有多餘的交換。也就是對於ai這個數,只能從i到ai這乙個方向走。考慮x,y,z三個數 x y z y需要和x z各交換一次,這顯然不能使y這個數滿足只向乙個方向移動這個條...