思路:維護當前數值的唯一表示法,然後根據唯一表示法來確定答案
任何乙個數\(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。我們不再討...