首页 > 其他分享 >【题解】Fibonacci-ish II

【题解】Fibonacci-ish II

时间:2023-10-10 10:36:31浏览次数:30  
标签:斐波 cur int 题解 tree II ish 那契 节点

传送门

题目分析

根据题目范围 \(n\le 30000\) 并且此题可以离线维护这个很恶心的东西,所以我们考虑莫队。由于要求访问到任意一个区间都要求知道它有序之后的序列,所以这个东西可以用权值线段树维护。因此,此题正解是莫队+权值线段树。

我们分类讨论一下加上一个数,删除一个数对答案的影响。

加上一个数相当于它自己的排名乘上对应的斐波那契数列,但在它右边的数乘上的斐波那契数列都要往右移一位。考虑推出知道向右边移 \(c\) 位(可能是负数)之后快速计算新增贡献的式子。也就是知道 \(f[i],f[c]\),怎么推出 \(f[i+c]\)。

严谨的证明?我不会。但我们可以大胆猜结论。
假设 \(c=1\),那么显然 \(f[i+1]=f[i]+f[i-1]\)。
假设 \(c=2\),那么 \(f[i+2]=f[i+1]+f[i]=f[i]+f[i-1]+f[i]=2f[i]+f[i-1]\)。
假设 \(c=3\),那么 \(f[i+3]=f[i+2]+f[i+1]=2f[i]+f[i-1]+f[i]+f[i-1]=3f[i]+2[i-1]\)。
...
再往下面枚举,或者你感性理解,会发现 \(f[i]\) 和 \(f[i-1]\) 前面的系数也是一个斐波那契数列,手玩一下得出 \(f[i+c]=f[i]\times f[c]+f[i-1]\times f[c-1]\) (斐波那契数列下标从 \(0\) 开始)。

所以对于线段树上的每一个节点,我们维护三个值 \(pre,v\) 表示上一位 \(f[i-1]\) 乘上这个节点的值和现在对应的 \(f[i]\) 乘上这个节点的值。

减去一个数相当于在它右边的数乘上的斐波那契数列都要往左移一位,接下来的处理和加一位一样,只是 \(c\) 为负数了。

实现

莫队是用来处理这个数在当前区间出现了几次,如果不是第一次我们就不用管。

//buc表示这个数出现了几次
inline void add(int x){
    buc[a[x]]++;
    if(buc[a[x]]==1){
        update(1,1,K,a[x],1);
    }
}
inline void del(int x){
    buc[a[x]]--;
    if(buc[a[x]]==0) update(1,1,K,a[x],-1);
}

权值线段树维护的是当前区间的答案。在更改函数中,如果要更改的节点在左子树,那么我们将右子树都打上一个向右/左移一位的标记,如果在右子树那么它对左子树显然是没影响的。更改到叶子节点时,如果是删除操作那么直接赋值为 \(0\),否则看它要往右移几位再更改。

为什么在叶子节点的赋值是 \(tree[cur].v=b[lt]\times f[K+tag[cur]+1]\),为什么是懒标记数组? 我们在右子树打上标记并不是只给现在有权值的节点打上标记,而是给所有节点都打上。显然左边有多少个节点这个节点就会被打上多少次标记,因此可以通过懒标记数组看它目前的排名。

inline void update(int cur,int lt,int rt,int qx,int opt){
//opt表示是向左移还是向右移,也就是opt=-1表示删除,opt=1表示添加
//b数组是离散化后对应的原数组
//K是一个常数,因为可能会往左移,为了防止数组下标为负数而加的
    if(lt==rt){
        if(opt==-1) tree[cur].pre=tree[cur].v=0;
        else{
            tree[cur].pre=1ll*b[lt]*f[K+tag[cur]]%mod;
            tree[cur].v=1ll*b[lt]*f[K+tag[cur]+1]%mod;
        }
        return;
    }
    pushdown(cur);
    int mid=(lt+rt)>>1;
    if(qx<=mid){
        update(cur<<1,lt,mid,qx,opt);
        addtag(cur<<1|1,opt);
    }
    else update(cur<<1|1,mid+1,rt,qx,opt);
    pushup(cur);
}

添上标记的函数直接上之前推的式子即可。

inline void addtag(int cur,int k){
    long long np=(1ll*tree[cur].pre*f[k-1+K]+1ll*tree[cur].v*f[k+K])%mod;
    long long nv=(1ll*tree[cur].pre*f[k+K]+1ll*tree[cur].v*f[k+1+K])%mod;
    tag[cur]+=k;
    tree[cur].pre=np;
    tree[cur].v=nv;
}

预处理斐波那契数列 \(f[i]\)

f[K+1]=f[K+2]=1;
for(int i=K+3;i<=K*2;++i){
	f[i]=f[i-1]+f[i-2];
	if(f[i]>=mod) f[i]-=mod;
	//    cout<<f[i]<<" ";
}
for(int i=K;i>=0;--i){
	f[i]=f[i+2]-f[i+1];
	if(f[i]<0) f[i]+=mod;
}

我们发现实际上的第 \(0\) 项是 \(K+1\),这就是为什么之前 addtag 函数中要乘上原本 \(+1\) 项的斐波那契数列了。

查询时直接返回 \(tree[1].v\) 即可。

注意本题有点卡常,不建议 #define int long long

总结

推式子时可以考虑从特殊到一般大胆猜结论。

标签:斐波,cur,int,题解,tree,II,ish,那契,节点
From: https://www.cnblogs.com/Cloote/p/17753981.html

相关文章

  • 题解 P3894【[GDOI2014] 传送】
    难倒不难,128MB的空间限制快恶心死我了。我们设\(d_{u_0,u_1}\)表示到节点\((u_0,u_1)\)距离最近的叶子的距离,这个可以很容易换根DP求出。设\(p_{u_0}\)表示树\(u_0\)中距离最近的两个叶子的距离。设\(dis(u_0,u_1,v_0,v_1)\)(\(u_0=v_0\))表示树中两个节点\(u_1\)和......
  • 【ABC322C】题解
    AtCoderBeginnerContest322ProblemC-Festival题解Meaning-题意简述给定\(N\)和\(M\),还有\(M\)个正整数\(a_1\sima_n\),对于每个\(i\len\),求出\(a\)中第一个大于等于\(i\)的整数和\(i\)的差。Solution-题解思路题目保证\(a\)数组单增,所以就可......
  • 【LG-P7617】题解
    题解思路不用关心每个数的每一位是什么、哪几位相同,我们只需记录每个数出现了哪几个数字,可以使用类似于状态压缩的思想记录每个数的状压形式,比如一个数为\((4)_{10}\),那么他的状态压缩形式为\((00001)_2\)。当两个数在状态压缩表示下有一位相同,我们就认为这两个数是一对,每个......
  • 【ABC322D】题解
    AtCoderBeginnerContest322ProblemD-Polyomino题解Meaning-题意简述给定三个字符矩阵,求它们能不能拼在一起变成一个\(4\times4\)的全部是#的矩阵。Solution-题解思路大模拟。说简单也不简单,很复杂;但是说难呢,又不难。思路:搜索每一个矩阵的状态。0x001旋......
  • P1220 关路灯 题解
    Description给定\(n\)个点的位置\(a_i\)和每秒的花费\(b_i\),你的初始位置是\(s\),你删掉一个点的时间为\(0\)秒,走\(1\)个单位长度的时间是\(1\)秒。请你确定一种关灯顺序,使得所有点的最终花费最小(删掉点后这个点不会再花费)。Solution每删掉一个点,有两种选择:继续往前......
  • 汉诺塔(河内塔)题解
    汉诺塔(河内塔)题解我们定义\(T_n\)为根据规则将\(n\)个圆盘从一根柱子移动到另一根柱子的最少移动步数,按照这样的定义,本道题的答案实际上就是\(T_n\)。通过手动模拟,可得到\(T_1=1,T_2=3\)。同时显然有\(T_0=0\),即表示\(0\)个圆盘根本无需做任何移动。接着我们开始考虑......
  • CF1142D Foreigner题解
    CF1142DForeigner题解前言:题目含义真的好难理解呜呜。遇到的dp套dp的第三题,所以深入进行了理解。参考博文:https://www.cnblogs.com/AWhiteWall/p/16479483.html题意简化:先定义了不充分。首先数字$[1,9]$都不充分,注意没有$0$。当这个数字(设为$x$)大于等于$10$时......
  • 题解 CF457F 【An easy problem about trees】
    尝试理解,感谢cz_xuyixuan的题解。算作是很多情况的补充说明。我们不妨先二分答案,将\(\gemid\)的设为\(1\),\(<mid\)的设为\(0\),于是问题转化为了权值均为\(0/1\)的版本。我们称一棵树的大小为其非叶节点数。我们称一棵大小为奇数的树为奇树,大小为偶数的树为偶树。对......
  • 题解 - CF1972E - Divisors and Table
    这题正解是虚树,本解法卡常,仅适合不会虚树的。(例如本人)注意:下文中根节点深度定义为1.第一步:转化问题我们把$g(x,y,z)$拆开,考虑每个质数是哪些点的因子。包含这个质数的点构成一个点集,我们只需求这个点集S的$\sum\limits_{x,y,z\inS}f(x,y,z)$。第二步:对......
  • P4801题解
    解题思路:确实是一道很好的贪心,但由于加上了水这个影响因素,使题目复杂度上升了不少。(考虑的东西多了嘛)输个入。对饼干温度无脑排序。求最小值。求最大值(用双指针做,后面会讲)。解题过程:先输入(这个步骤就不用我讲了)inta[1000005];longlongn,ws;longlongmin......