CF 316E3(Summer Homework-广意Fib数列在p,q=1时的性质-Fib线段树)

本文解析了一道复杂的算法题目,介绍了如何通过构建特殊的数据结构和运用斐波那契数列特性来高效处理一系列更新与查询操作。

E3. Summer Homework
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

By the age of three Smart Beaver mastered all arithmetic operations and got this summer homework from the amazed teacher:

You are given a sequence of integers a1, a2, ..., an. Your task is to perform on it m consecutive operations of the following type:

  1. For given numbers xi and vi assign value vi to element axi.
  2. For given numbers li and ri you've got to calculate sum , where f0 = f1 = 1 and at i ≥ 2fi = fi - 1 + fi - 2.
  3. For a group of three numbers li ri di you should increase value ax by di for all x (li ≤ x ≤ ri).

Smart Beaver planned a tour around great Canadian lakes, so he asked you to help him solve the given problem.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 2·105) — the number of integers in the sequence and the number of operations, correspondingly. The second line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 105). Then follow m lines, each describes an operation. Each line starts with an integer ti (1 ≤ ti ≤ 3) — the operation type:

  • if ti = 1, then next follow two integers xi vi (1 ≤ xi ≤ n, 0 ≤ vi ≤ 105);
  • if ti = 2, then next follow two integers li ri (1 ≤ li ≤ ri ≤ n);
  • if ti = 3, then next follow three integers li ri di (1 ≤ li ≤ ri ≤ n, 0 ≤ di ≤ 105).

The input limits for scoring 30 points are (subproblem E1):

  • It is guaranteed that n does not exceed 100m does not exceed 10000 and there will be no queries of the 3-rd type.

The input limits for scoring 70 points are (subproblems E1+E2):

  • It is guaranteed that there will be queries of the 1-st and 2-nd type only.

The input limits for scoring 100 points are (subproblems E1+E2+E3):

  • No extra limitations.

Output

For each query print the calculated sum modulo 1000000000 (109).

Sample test(s)
input
5 5
1 3 1 2 4
2 1 4
2 1 5
2 2 4
1 3 10
2 1 5
output
12
32
8
50
input
5 4
1 3 1 2 4
3 1 4 1
2 2 4
1 2 10
2 1 5
output
12
45


艰难滴完成了E题……感觉不会再爱了

好吧,题目那个解法由于智商太低没看懂……

说一下我最后乱推的结果

设S(0)=F1a1+F2a2+..+Fnan

+)S(1)=F2a2+F3a3+..+F3a3

=       (F1+F2)a2+(F2+F3)a3+..+(Fn-1+Fn)an

=          F3      a3+    F4     a3+..+      Fn+1  an

于是我XXXXX……

只要存S0和S1就行了   Sx可以用关于S0和S1的表达式表示:Sx=Fn-2*S0 +Fn-1*S1 (系数为什么是Fib数?因为Sx=Sx-1+Sx-2的不明公式,可用数学归纳法证)


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MAXN (200000+10)
#define F (1000000000)
#define Lson (x<<1)
#define Rson ((x<<1)+1)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
//void inv(long long a,long long b){return exgcd(a,}
int n,m;
long long f[MAXN],sf[MAXN]={0},f2[MAXN],sf2[MAXN];
struct arr_t
{
    long long a[MAXN*4],s0[MAXN*4],s1[MAXN*4],b[MAXN*4];
    arr_t(){MEM(a)MEM(s0)MEM(s1)MEM(b)}
    long long S(int x,int n) //求的是S(x)
    {
        if (n==1) return s0[x];
        if (n==2) return s1[x];
        return add(mul(f[n-2],s0[x]),mul(f[n-1],s1[x]));
    }
    void update(int x,int l,int r)
    {
        int n=r-l+1,m=(l+r)>>1,ls=m-l+1,rs=n-ls;
        s0[x]=(s0[Lson]+S(Rson,ls+1))%F;
        s1[x]=(s1[Lson]+S(Rson,ls+2))%F;
    }
    void change(int x,int n,int c)
    {
        s0[x]=add(s0[x],mul(sf[n],c));
        s1[x]=add(s1[x],mul(sf2[n],c));
    }
    void pushdown(int x,int l,int r)
    {
        if (l==r) return;
        else if (b[x])
        {
            int n=r-l+1,m=(l+r)>>1,ls=m-l+1,rs=n-ls;
            s0[Lson]=add(s0[Lson],mul(sf[ls],b[x]));
            s0[Rson]=add(s0[Rson],mul(sf[rs],b[x]));
            s1[Lson]=add(s1[Lson],mul(sf2[ls],b[x]));
            s1[Rson]=add(s1[Rson],mul(sf2[rs],b[x]));
            b[Lson]+=b[x];b[Rson]+=b[x];b[x]=0;
        }
    }
    void ins(int x,int l,int r,int L,int R,int c)
    {
        pushdown(x,l,r);
        int n=r-l+1,m=(l+r)>>1;
        if (L<=l&&r<=R) {b[x]+=c;change(x,n,c);return;}
        if (L<=m) ins(Lson,l,m,L,R,c);
        if (m<R) ins(Rson,m+1,r,L,R,c);
        update(x,l,r);
    }
    void modify(int x,int l,int r,int L,int c)
    {
        pushdown(x,l,r);
        int n=r-l+1,m=(l+r)>>1;
        if (l==r) {s0[x]=s1[x]=c;return;}
        if (L<=m) modify(Lson,l,m,L,c);
        else modify(Rson,m+1,r,L,c);
        update(x,l,r);
    }

    void build(int x,int l,int r)
    {
        if (l==r) {scanf("%d",&a[x]);s0[x]=s1[x]=a[x]; return ;}
        int n=r-l+1,m=(l+r)>>1;
        build(Lson,l,m);
        build(Rson,m+1,r);
        update(x,l,r);
    }
    long long qur(int x,int l,int r,int L,int R)
    {
        pushdown(x,l,r);
        int n=r-l+1,m=(l+r)>>1;
        if (L<=l&&r<=R) {return S(x,l-(L-1));}
        long long ans=0;
        if (L<=m) ans=add(ans,qur(Lson,l,m,L,R));
        if (m<R) ans=add(ans,qur(Rson,m+1,r,L,R));
        return ans;
    }
}T;
int main()
{
	//freopen("homework.in","r",stdin);
	//freopen(".out","w",stdout);
    scanf("%d%d",&n,&m);
    f[1]=f[2]=sf[1]=1,sf[2]=2;Fork(i,3,n) f[i]=(f[i-1]+f[i-2])%F,sf[i]=(sf[i-1]+f[i])%F;
    f2[1]=sf2[1]=1,f2[2]=2;sf2[2]=3;Fork(i,3,n) f2[i]=(f2[i-1]+f2[i-2])%F,sf2[i]=(sf2[i-1]+f2[i])%F;

    T.build(1,1,n);
    For(i,m)
    {
        int p,x,v,l,r,d;scanf("%d",&p);
        if (p==1)
        {
            scanf("%d%d",&x,&v);T.modify(1,1,n,x,v);
        }
        else if (p==2)
        {
            scanf("%d%d",&l,&r);cout<<T.qur(1,1,n,l,r)<<endl;
        }
        else
        {
            scanf("%d%d%d",&l,&r,&d);T.ins(1,1,n,l,r,d);

        }
    }


	return 0;
}


<think>好的,我现在需要帮助用户理解为什么在生成斐波那契数列的第三项,代码中使用fib[-1]和fib[-2]会得到1。用户的问题是“fib[-1] = 1fib[-1]是什么意思”。首先,我需要确定用户对Python列表索引的理解程度,尤其是负数索引的用法。 首先,用户可能对负数索引不太熟悉,所以需要解释清楚。负数索引在Python中表示从列表末尾开始计数,比如fib[-1]是最后一个元素,fib[-2]是倒数第二个元素。当用户看到fib[-1] = 1,可能不理解这里的-1代表什么,特别是当列表中有多个元素。 接下来,用户提到的例子中,当n=3,前两项已经初始化为[1, 1],所以这个fib列表有两个元素。这fib[-1]确实是第二个元素,也就是1,而fib[-2]是第一个元素,也是1。因此,它们的和就是2,作为第三项添加进去。 用户可能存在的疑问还包括,为什么不用fib[1]和fib[0],而是用负数索引。这候需要解释负数索引的好处,尤其是在列表长度动态变化,不需要知道具体长度就能获取最后几个元素,这在循环生成斐波那契数列非常方便,因为每次循环都会添加新元素,列表长度不断增加,使用负数索引可以始终访问最新的两个元素。 另外,用户可能对索引的起始位置有疑问,比如是否从0开始,负数索引的范围是什么。需要明确说明,在Python中,列表索引从0开始,负数索引-1表示最后一个元素,-2表示倒数第二个,依此类推,如果列表长度为2,那么fib[-1]就是索引1的元素,fib[-2]是索引0的元素。 可能还需要举例说明不同列表长度下负数索引对应的元素,帮助用户更直观地理解。例如,如果列表是[1, 1, 2],那么fib[-1]是2fib[-2]是1,这样生成下一项会得到3。 最后,需要确认用户是否理解了斐波那契数列的生成逻辑,即每一项都是前两项之和,而负数索引在这里的作用是方便地获取前两项的值,无论列表有多长,这样代码可以更简洁和通用。</think>好的!我来用中文详细解释 `fib[-1]` 的含义以及为什么在这个场景下它会等于 `1`。 --- ### **1. Python列表的负数索引** 在Python中,**负数索引**表示从列表的**末尾开始计数**: - `fib[-1]`:列表的**最后一个元素** - `fib[-2]`:列表的**倒数第二个元素** - 以此类推(例如 `fib[-3]` 是倒数第三个元素) **例如**: ```python fib = [1, 1, 2, 3] print(fib[-1]) # 输出 3(最后一个元素) print(fib[-2]) # 输出 2(倒数第二个元素) ``` --- ### **2. 你的案例中 `fib[-1]` 为什么等于 `1`?** 当代码执行到生成第三项,`fib` 列表的状态是 `[1, 1]`(已初始化前两项): - `fib = [1, 1]`(长度为2- **索引分析**: - `fib[0] = 1`(第一个元素,索引从0开始) - `fib[1] = 1`(第二个元素) - `fib[-1] = fib[1] = 1`(最后一个元素) - `fib[-2] = fib[0] = 1`(倒数第二个元素) **计算过程**: ```python next_num = fib[-1] + fib[-2] # 1 + 1 = 2 ``` --- ### **3. 为什么用负数索引?** 负数索引的优点是: 1. **动态获取末尾元素**:无论列表多长,`fib[-1]` 始终指向最后一个元素,无需手动计算长度。 2. **代码简洁**:避免使用 `fib[len(fib)-1]` 这种冗长的写法。 **示例对比**: ```python # 用正数索引(需要知道长度) last = fib[len(fib)-1] second_last = fib[len(fib)-2] # 用负数索引(更简洁) last = fib[-1] second_last = fib[-2] ``` --- ### **4. 关键总结** | 表达式 | 含义 | 当前列表 `[1, 1]` 中的值 | |--------------|-----------------------|---------------------------| | `fib[-1]` | 列表最后一个元素 | `1` | | `fib[-2]` | 列表倒数第二个元素 | `1` | | `fib[-1] + fib[-2]` | 最后两项相加生成新项 | `1 + 1 = 2` | --- ### **5. 进一步验证** 假设 `fib` 后续扩展为 `[1, 1, 2, 3, 5]`: - `fib[-1] = 5`(最后一个元素) - `fib[-2] = 3`(倒数第二个元素) - 下一项将是 `5 + 3 = 8`。 负数索引始终保持对“最新两项”的动态追踪,这正是斐波那契数列生成的核心逻辑!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值