CEOI2018 斐波那契表示法

2022-05-20 04:48:11 字數 2744 閱讀 2178

思路:維護當前數值的唯一表示法,然後根據唯一表示法來確定答案

任何乙個數\(x\)有唯一表示\(p_i\),滿足\(x=\sum f_,p_i

即不會出現相鄰兩項

依次插入每乙個數\(x\),考慮可能出現的情況

1.\(x\)一位以及前後為空,那麼直接插入

2.\(x\)一位為空,且\(x-1\)為空,\(x+1\)已經出現

刪除\(x+1\),插入\(x+2\)

3.\(x\)一位為空,且\(x+1\)為空,\(x-1\)已經出現

刪除\(x-1\),插入\(x+1\)

4.\(x\)一位有

先刪除\(x\),然後插入\(x+1,x-2\)

對於操作1,2,3以及4中的\(x+1\),每次操作增加\(o(1)\)個元素,每次遞迴進行刪除\(o(1)\)個元素

操作次數為均攤\(o(n)\)

對於\(4\)操作中的\(x-2\),如果\(x-2\)已經出現就會不斷進行遞迴

最終的效果就是所有被操作到的\(x-2,x-4,x-6\ldots\)向右平移了一位

大致如此,實際情況比較複雜,要討論x-2=0,x-2<0等等情況

用一棵平衡樹維護\(p_i-p_\)的值即可,4操作可以二分左邊第乙個》2的元素,然後進行平移

最終複雜度為\(o(n\log n)\)

\[\

\]令邊界\(p_0=0\),根據上面維護的\(\delta_i=p_i-p_\)

考慮根據\(\delta_i\)求解答案

顯然乙個數\(x\)可以下分為\(x\)或者\(x-1,x-2\) 或 \(x-1,x-3,x-4\) 或\(x-1,x-3,x-5,x-6\ldots\)

且不能碰到前面的數

簡單分析發現\(p_i\)有$\lceil \frac\rceil $種下分方案

然而,\(p_\)如果被下分,那麼\(p_\)這一位會消失,變成\(p_-1\)作為限制點

也就是說,\(p_\)的下分會影響到\(\delta_i\),使得\(\delta_i\rightarrow \delta_i+1\)

那麼依次考慮每個\(\delta_i\),令\(dp_\)表示前\(i\)個,最後乙個是否下分的方案數,可以\(dp\)求解

由於要動態維護,因此可以考慮用乙個類似矩陣的東西來維護區間的dp情況

在平衡樹中\(up\)維護答案即可

#includeusing namespace std;

typedef long long ll;

typedef pair pii;

#define reg register

#define mp make_pair

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

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

template inline void cmin(t &a,t b)

template inline void cmax(t &a,t b)

const int n=4e5+10,p=1e9+7;

int n;

struct node

node()

node(int x)

}node operator + (const node _) const

} s[n],val[n];

int rt,ls[n],rs[n],key[n];

void up(int x)

int u(int x,int y) else

}void eraseend(int &x)

static int t[n],c;

for(int y=x;y;y=rs[y]) t[++c]=y;

rs[t[c-1]]=ls[t[c]];

drep(i,c-1,1) up(t[i]);

c=0;

}void addr(int x,int y)

void addl(int x,int y)

pii split(int x) else

}pii split2(int x) else

}int new(int x)

void ins(int x)

if(s[rt].len1)

t.first=u(y.first,y.second);

}if(s[t.first].len==x+1)

int d=s[t.first].len-x;

addr(t.first,-d);

rt=u(u(t.first,new(d)),t.second);

return;

}if(s[t.second].l==2) return addl(t.second,s[t.first].r),eraseend(t.first),rt=u(t.first,t.second),ins(x+1),ins(x-2);

pii y=split(t.first); addl(t.second,-1);

if(!y.first)

rt=u(u(new(1),y.second),t.second);

return;

} if(s[y.first].len>3 && s[y.first].r==3)

addr(y.first,-2);

rt=u(u(u(y.first,new(3)),y.second),t.second);

}int main()

斐波那契數列 斐波那契數列python實現

斐波那契數列 fibonacci sequence 又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 在數學上,斐波納契數列以如下被以遞推的方法定義 f 1 ...

迴圈斐波那契數列 斐波那契數列應用

什麼是斐波那契數列 斐波那契數列指的是這樣乙個數列 1,1,2,3,5,8,13,21,34,55,89,144 這個數列從第3項開始,每一項都等於前兩項之和 台階問題 有一段樓梯有10級台階,規定每一步只能跨一級或兩級,要登上第10級台階有幾種不同的走法?這就是乙個斐波那契數列 登上第一級台階有一...

分治法例項 斐波那契數列

我們都十分熟悉斐波那契數列的定義 fn fn 1 fn 2,其中f0 0 f1 1。那麼我們如何求解斐波那契數列的某個特定項呢?方法一 遞迴求解。這種方法看似簡單,可是實際上我們會重複計算許多已經計算過的項,最後遞迴樹竟然是一棵完全二叉樹,時間複雜度達到了 n 其中 sqrt 5 1 2。我們不再討...