题解 CF446C 【DZY Loves Fibonacci Numbers】

# 题解 CF446C
这是一道数据结构题。

我们先翻译下题目:

给你一个n,给你一个长度为n的序列,给你一个m,给你m此操作,包括区间修改和查询,修改为在一个区间内每个数加上他所对应的斐波那契数,查询为查询区间和。

一看到区间修改和区间查询,我们就可以知道这是一道线段树的题目(不要问我怎么知道的,~~我也想知道~~)

进入正题:

我们一定要找到一种方法,维护区间和。

我们可以先把斐波那契数列的每一项拆开,找规律,我们会发现:

$$f_1=f_1,f_2=f_2$$
$$f_3=f_1+f_2,f_4=f_1+2*f_2$$
$$f_5=2*f_1+3*f_2,f_6=3*f_1+5*f_2$$

我们可以找到规律

$$f_i=f_{i-1}*f_2+f_{i-2}*f_1$$

因为在区间内加入一个斐波那契数列,这个区间任然满足斐波那契数列的关系,只是$f_1$和$f_2$变了而已,所以,我们可以用{a}来维护这个斐波那契数列,即可表示为:

$$a_i=f_{i-1}*a_2+f_{i-2}*a_1$$

因为是维护区间和,所以我们需要累加和,故,我们再将式子拆开,可以得到:

$$s_3=2*a_1+2*a_2$$
$$s_4=3*a_1+4*a_2$$
$$s_5=5*a_1+7*a_2$$

经过观察和归纳,我们可以发现:

$$\sum_ {i=1}^n a_i = f_n*a_1+(f_{n+1}-1)*a_2$$

于是我们就可一开始做这道题了。

我们用两个懒惰标记,分别为$f1$和$f2$,来维护某一段区间的和,当我们要求这段区间的和时,我们只要用上面那个公式求出区间和,然后加入值中就行了。

---------------------------------------------------我是~~超级可爱~~的分割线-------------------------------------------------

代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=300009;
const ll P=1e9+9;
int n,m;
ll f[N];
struct Segtree
{
ll v,f1,f2;
}tree[N<<2];
inline ll read()
{
ll x=0,flag=1;
char ch=getchar();
while(ch>‘9‘||ch<‘0‘) {if(ch==‘-‘) ch=getchar();flag=-1;}
while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
return x*flag;
}
void build(int k,int l,int r)
{
if(l==r)
{
tree[k].v=read();
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
tree[k].v%=P;
}
void push_down(int k,int l,int r) //标记下传
{
if(!(tree[k].f1==0 && tree[k].f2==0))
{
int mid=(l+r)>>1;
tree[k<<1].f1+=tree[k].f1;
tree[k<<1].f1%=P;
tree[k<<1].f2+=tree[k].f2;
tree[k<<1].f2%=P;
tree[k<<1].v+=tree[k].f2*(f[mid-l+2]-1)+tree[k].f1*f[mid-l+1];
tree[k<<1].v%=P;
int pos=mid-l+2;
tree[k<<1|1].f1+=f[pos-1]*tree[k].f2+f[pos-2]*tree[k].f1;
tree[k<<1|1].f1%=P;
tree[k<<1|1].f2+=f[pos]*tree[k].f2+f[pos-1]*tree[k].f1;
tree[k<<1|1].f2%=P;
tree[k<<1|1].v+=tree[k].f2*(f[r-l+2]-1)+tree[k].f1*f[r-l+1]-tree[k].f2*(f[mid-l+2]-1)-tree[k].f1*f[mid-l+1];
tree[k<<1|1].v%=P;
tree[k].f1=0,tree[k].f2=0;
}
}
void modify(int k,int l,int r,int x,int y)
{
if(l>y || r<x) return;
if(l>=x && r<=y)
{
tree[k].f1+=f[l-x+1];
tree[k].f1%=P;
tree[k].f2+=f[l-x+2];
tree[k].f2%=P;
tree[k].v+=f[r-l+1]*f[l-x+1]%P+(f[r-l+2]-1)*f[l-x+2]%P;
tree[k].v%=P;
return;
}
int mid=(l+r)>>1;
push_down(k,l,r);
modify(k<<1,l,mid,x,y);
modify(k<<1|1,mid+1,r,x,y);
tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
tree[k].v%=P;
}
void init()
{
f[1]=1,f[2]=1;
for(int i=3;i<=n+1;i++) f[i]=f[i-1]+f[i-2],f[i]%=P;
}
ll query(int k,int l,int r,int x,int y)
{
if(l>y || r<x) return 0;
if(l>=x && r<=y) return tree[k].v;
push_down(k,l,r);
int mid=(l+r)>>1;
return (query(k<<1,l,mid,x,y)+query(k<<1|1,mid+1,r,x,y))%P;
}

int main()
{
n=read();m=read();
build(1,1,n);
init();
for(int i=1;i<=m;i++)
{
int t=read(),x=read(),y=read();
if(t==1) modify(1,1,n,x,y);
else printf("%lld\n",(query(1,1,n,x,y)%P+P)%P);
}
return 0;
}
```

~~垃圾数据结构~~

原文地址:https://www.cnblogs.com/qshjydzh/p/12248586.html

时间: 2024-10-29 00:16:42

题解 CF446C 【DZY Loves Fibonacci Numbers】的相关文章

CF446C DZY Loves Fibonacci Numbers 线段树 + 数学

code: #include <bits/stdc++.h> #define N 400004 #define LL long long #define lson now<<1 #define rson now<<1|1 #define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace

codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)

In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 = 1; F2 = 1; Fn = Fn - 1 + Fn - 2 (n > 2). DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: a1, a2, ...,

Codeforces446C DZY Loves Fibonacci Numbers(线段树 or 分块?)

第一次看到段更斐波那契数列的,整个人都不会好了.事后看了题解才明白了一些. 首先利用二次剩余的知识,以及一些数列递推式子有下面的 至于怎么解出x^2==5(mod 10^9+9),我就不知道了,但是要用的时候可以枚举一下,把这些参数求出来之后就题目就可以转化为维护等比数列. 由于前面的常数可以最后乘,所以就等于维护两个等比数列好了. 下面我们来看如何维护一个等比数列.假如我对区间[L,R]的加上1,2,4,8...2^n的话,那么我只需要加一个标记x表示这个区间被加了多少次这样的2^n. 举个例

Codeforces446C - DZY Loves Fibonacci Numbers

Portal Description 给出一个\(n(n\leq3\times10^5)\)个数的序列,进行\(m(m\leq3\times10^5)\)次操作,操作有两种: 给区间\([L,R]\)加上一个斐波那契数列,即\(\{a_L,a_{L+1},...,a_R\} \rightarrow \{a_L+F_1,a_{L+1}+F_2,...,a_R+F_{R-L+1}\}\) 询问区间\([L,R]\)的和,对\(10^9+9\)取模. 斐波那契数列:\(F_1=1,F_2=2\)且满足

codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新

DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-14) Description In mathematical terms, the sequence Fn of Fibonacci numbers is defi

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. f[n] 是斐波那契数列 也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少 通过简单的公式叠加也能求和 F[n]  = f[n - 1] * b + f[n - 2] * a F[n - 1] = f[n - 2] * b + f[n - 3] * a ..

[CodeForces - 447E] E - DZY Loves Fibonacci Numbers

E  DZY Loves Fibonacci Numbers In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1?=?1; F2?=?1; Fn?=?Fn?-?1?+?Fn?-?2 (n?>?2). DZY loves Fibonacci numbers very much. Today DZY gives you an array consist

【CF446C】DZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)

Description ? 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solution ? 先来考虑一段斐波那契数列如何快速求和,根据性质有 \[ \begin {align} fib_n &= fib_{n - 1} + fib_{n - 2} \ &= fib_ {n - 2} + fib_{n - 3} + fib_{n - 2} \ &= fib_{n -

CF446C [DZY loves Fibonacci]

Description Transmission Gate 你需要维护一个长度为\(n \leq 300000\) 的数列,兹词两个操作: 1.给一个区间加上一个fibonacci数列,规定\(f[0] = 0, f[1] = 1, f[2] = 1\) 2.查询一段区间的和.对1e9+9取模 操作个数m不超过300000. Solution ? 这一题其实要考虑Fibonacci数列的两个性质: ? (i)\(\sum_{i = 1}^{n} fib(i) = f(n + 2) - 1\) ?