「CEOI2018」斐波那契表示法
思路:维护当前数值的唯一表示法,然后根据唯一表示法来确定答案
Part1 唯一表示法
任何一个数(x)有唯一表示(P_i),满足(x=sum F_{P_i},P_i<P_{i+1}-1)
即不会出现相邻两项
依次插入每一个数(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-6ldots)向右平移了一位
大致如此,实际情况比较复杂,要讨论x-2=0,x-2<0等等情况
用一棵平衡树维护(P_i-P_{i-1})的值即可,4操作可以二分左边第一个>2的元素,然后进行平移
最终复杂度为(O(nlog n))
Part2 dp求答案
令边界(P_0=0),根据上面维护的(delta_i=P_i-P_{i-1})
考虑根据(delta_i)求解答案
显然一个数(x)可以下分为(x)或者(x-1,x-2) 或 (x-1,x-3,x-4) 或(x-1,x-3,x-5,x-6ldots)
且不能碰到前面的数
简单分析发现(P_i)有$lceil frac{delta_i}{2} ceil $种下分方案
然而,(P_{i-1})如果被下分,那么(P_{i-1})这一位会消失,变成(P_{i-1}-1)作为限制点
也就是说,(P_{i-1})的下分会影响到(delta_i),使得(delta_i ightarrow delta_i+1)
那么依次考虑每个(delta_i),令(dp_{i,f})表示前(i)个,最后一个是否下分的方案数,可以(dp)求解
由于要动态维护,因此可以考虑用一个类似矩阵的东西来维护区间的dp情况
在平衡树中(up)维护答案即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <int,int> 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 <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
char IO;
template <class T=int> T rd(){
T s=0; int f=0;
while(!isdigit(IO=getchar())) f|=IO=='-';
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
const int N=4e5+10,P=1e9+7;
int n;
struct Node{
int l,r,ma,len;
int a[2][2];
void clear(){ memset(a,0,sizeof a); }
Node(){ }
Node(int x){
l=r=ma=len=x;
rep(i,0,1) {
a[i][0]=1;
a[i][1]=(x-1+i)/2;
}
}
Node operator + (const Node _) const {
Node res; res.l=l,res.r=_.r,res.ma=max(ma,_.ma),res.len=len+_.len;
res.a[0][0]=(1ll*a[0][0]*_.a[0][0]+1ll*a[0][1]*_.a[1][0])%P;
res.a[1][0]=(1ll*a[1][0]*_.a[0][0]+1ll*a[1][1]*_.a[1][0])%P;
res.a[0][1]=(1ll*a[0][0]*_.a[0][1]+1ll*a[0][1]*_.a[1][1])%P;
res.a[1][1]=(1ll*a[1][0]*_.a[0][1]+1ll*a[1][1]*_.a[1][1])%P;
return res;
}
} s[N],val[N];
int rt,ls[N],rs[N],key[N];
void Up(int x){
s[x]=val[x];
if(ls[x]) s[x]=s[ls[x]]+s[x];
if(rs[x]) s[x]=s[x]+s[rs[x]];
}
int U(int x,int y){
if(!x||!y) return x|y;
if(key[x]<key[y]) return rs[x]=U(rs[x],y),Up(x),x;
return ls[y]=U(x,ls[y]),Up(y),y;
}
Pii Lower(int x,int len){
if(len<=0 || !x) return mp(0,x);
if(s[x].len<=len) return mp(x,0);
if(s[ls[x]].len>=len) {
Pii y=Lower(ls[x],len);
return ls[x]=y.second,Up(x),mp(y.first,x);
} else {
Pii y=Lower(rs[x],len-s[ls[x]].len-val[x].len);
return rs[x]=y.first,Up(x),mp(x,y.second);
}
}
void EraseEnd(int &x){
if(!rs[x]){ x=ls[x]; return; }
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){
if(!x) return;
if(rs[x]) return AddR(rs[x],y),Up(x);
val[x]=Node(val[x].len+y),Up(x);
}
void AddL(int x,int y){
if(!x) return;
if(ls[x]) return AddL(ls[x],y),Up(x);
val[x]=Node(val[x].len+y),Up(x);
}
Pii Split(int x){
if(s[x].ma<=2) return mp(0,x);
if(val[x].ma<=2 && s[rs[x]].ma<=2) {
Pii y=Split(ls[x]);
return ls[x]=y.second,Up(x),mp(y.first,x);
} else {
Pii y=Split(rs[x]);
return rs[x]=y.first,Up(x),mp(x,y.second);
}
}
Pii Split2(int x){
if(s[x].ma<=2) return mp(x,0);
if(s[ls[x]].ma>2 || val[x].ma>2) {
Pii y=Split2(ls[x]);
return ls[x]=y.second,Up(x),mp(y.first,x);
} else {
Pii y=Split2(rs[x]);
return rs[x]=y.first,Up(x),mp(x,y.second);
}
}
int New(int x){ return key[++n]=rand(),s[n]=val[n]=Node(x),n; }
void Ins(int x){
if(x<0) return;
cmax(x,1);
if(!rt) { rt=New(x); return; }
if(s[rt].len<x-1) {
rt=U(rt,New(x-s[rt].len));
return;
}
if(s[rt].len==x-1) {
EraseEnd(rt);
return Ins(x+1);
}
Pii t=Lower(rt,x);
if(s[t.first].len!=x) {
if(x>1) {
Pii y=Lower(t.first,x-1);
if(s[y.first].len==x-1) {
AddR(y.first,s[y.second].len),rt=U(y.first,t.second);
return Ins(x+1);
}
t.first=U(y.first,y.second);
}
if(s[t.first].len==x+1) {
Pii y=Split2(t.second);
AddL(y.second,-1);
int d=s[t.first].r+s[y.first].len+1;
EraseEnd(t.first);
rt=U(U(t.first,New(d)),y.second);
return;
}
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) {
if(s[y.second].l==1) {
AddL(y.second,1),rt=U(y.second,t.second);
return;
}
rt=U(U(New(1),y.second),t.second);
return;
}
if(s[y.first].len>3 && s[y.first].r==3) {
EraseEnd(y.first),AddR(y.first,2);
rt=U(U(U(y.first,New(2)),y.second),t.second);
return;
}
AddR(y.first,-2);
rt=U(U(U(y.first,New(3)),y.second),t.second);
}
int main(){
rep(kase,1,rd()) Ins(rd()),printf("%d
",(s[rt].a[0][0]+s[rt].a[0][1])%P);
}