首页 > 其他分享 >Sasha and Array 题解

Sasha and Array 题解

时间:2023-11-01 19:44:32浏览次数:39  
标签:Node return int 题解 sqrt Sasha res Array mod

Sasha and Array

题目大意

给定一个长为 \(n\) 的序列 \(a\),支持以下操作:

  • \(\forall i \in[l,r],a_i\gets a_i +x\)。

  • 求 \(\left(\sum\limits_{i=l}^{r}F_{a_i}\right)\bmod (10^9+7)\),其中 \(F\) 表示斐波那契数列,即有 \(F_1=1,F_2=1,\forall i>2,F_i=F_{i-1}+F_{i-2}\)。

思路分析

给出一种与现有题解完全不一样的方法。

我们都知道,斐波那契数列存在通项公式,即有:

\[F_{n}=\frac{1}{\sqrt{5}}\left(\left(\frac{1+\sqrt 5}{2}\right)^n-\left(\frac{1-\sqrt 5}{2}\right)^n\right) \]

(通项公式的推导本文不再赘述。)

那么,我们就可以将斐波那契数列看成两个等比数列的差,我们只需要维护等比数列就可以了。

不难发现,我们可以用线段树维护等比数列的值的和,那么区间加就变成了区间乘,也就是说,我们只需要维护一颗支持区间求和,区间乘的线段树就行了,而这是容易做到的。

但问题出现了,我们的所有操作都是在模 \(10^9+7\) 意义下进行的,我们发现,\(5\) 是模 \(10^9+7\) 的二次非剩余,也就是说,我们找不到一个 \(x\in[0,10^9+7)\) 使得 \(x^2=5\),那么这就意味着 \(\sqrt 5\) 无法直接参与模运算。

考虑扩域,我们将所有数表示为 \(A\sqrt 5+B\) 的形式,其中 \(A,B\) 都是正整数,可以直接参与模运算。那么我们只需要证明加法,减法,乘法和除 \(\sqrt 5\) 这四种运算均对该域封闭即可。

\[\begin{cases} (A\sqrt 5 + B) + (C\sqrt 5 + D) = (A+C)\sqrt 5 + (B+D)\\ (A\sqrt 5 + B) - (C\sqrt 5 + D) = (A-C)\sqrt 5 + (B-D)\\ (A\sqrt 5 + B)\times (C\sqrt 5 + D)= (AD+BC)\sqrt 5 + (5AC+BD)\\ (A\sqrt 5 + B)\times \dfrac{1}{\sqrt 5} = (\dfrac{1}{5}B)\sqrt 5 + (A)\\ \end{cases}\]

因为 \(5\) 在模 \(10^9+7\) 意义下有逆元,因此我们证明了这四种运算对该域封闭。

那么我们就可以愉快的直接套通项公式和线段树解决这道题了。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;
const int N = 200200, mod = 1000000007;
#define inf 0x3f3f3f3f
#define int long long
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid ((l + r) >> 1)

#define getchar() (p1 == p2 && (p2 = (p1 = BS) + fread(BS, 1, 1 << 16, stdin), p1 == p2) ?EOF : *p1 ++)
char BS[1 << 16], *p1 = BS, *p2 = BS;
template <typename Tp> void read(Tp &x){
    x=0; bool f = 0; char ch = getchar();
    while (ch > '9' || ch < '0') f |= ch == '-', ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    if(f) x = -x;
}
template <typename types, typename... Args> void read(types &x, Args&... args){
    read(x), read(args...);
}
template <typename Tp> void write(Tp x){
    if(x < 0) {putchar('-'); x = -x;}
    Tp k = x / 10; if(k) write(k);
    putchar(x - (k << 3) - (k << 1) + '0');
}
template <typename Tp> void print(Tp x, bool space = 0){
    write(x); 
    if (space) putchar(' ');
    else putchar('\n');
}

int n, q, in1, in2, in3, op, inv2, inv5;
int inp[N];

struct Node{
    int A, B;
    friend Node operator + (Node a, Node b){
        return {(a.A + b.A) % mod, (a.B + b.B) % mod};
    }
    friend Node operator - (Node a, Node b){
        return {(a.A - b.A + mod) % mod, (a.B - b.B) % mod};
    }
    friend Node operator * (Node a, Node b){
        return {(a.A * b.B % mod + b.A * a.B % mod) % mod, (5 * a.A % mod * b.A % mod + a.B * b.B % mod) % mod};
    }
    friend bool operator == (Node a, Node b){
        return (a.A == b.A) && (a.B == b.B);
    }
};

int q_powint(int a, int b){
    int res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

Node q_pow(Node a, int b){
    Node res = {0, 1};
    while (b) {
        if (b & 1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

Node frac(Node a){
    return Node{a.B * inv5 % mod, a.A};
}

struct STn{
    Node sum1, sum2, tag1, tag2;
};
struct ST{
    STn a[N << 2];
    STn merge(STn a, STn b){
        return STn{a.sum1 + b.sum1, a.sum2 + b.sum2, {0, 1}, {0, 1}};
    }
    void build(int p, int l, int r){
        a[p].tag1.B = a[p].tag2.B = 1;
        if (l == r) {
            a[p].sum1 = q_pow(Node{inv2, inv2}, inp[l]);
            a[p].sum2 = q_pow(Node{mod - inv2, inv2}, inp[l]);
            return ;
        }
        build(ls, l, mid); build(rs, mid + 1, r);
        a[p] = merge(a[ls], a[rs]);
    }
    void change_t(int p, Node k1, Node k2){
        a[p].sum1 = a[p].sum1 * k1;
        a[p].tag1 = a[p].tag1 * k1;
        a[p].sum2 = a[p].sum2 * k2;
        a[p].tag2 = a[p].tag2 * k2;
    }
    void push_down(int p){
        if ((a[p].tag1 == Node{0, 1}) && (a[p].tag2 == Node{0, 1})) return ;
        change_t(ls, a[p].tag1, a[p].tag2);
        change_t(rs, a[p].tag1, a[p].tag2);
        a[p].tag1 = a[p].tag2 = Node{0, 1};
    }
    void change(int p, int l, int r, int x, int y, Node k1, Node k2){
        if (x <= l && r <= y) return change_t(p, k1, k2);
        push_down(p);
        if (x <= mid) change(ls, l, mid, x, y, k1, k2);
        if (y > mid) change(rs, mid + 1, r, x, y, k1, k2);
        a[p] = merge(a[ls], a[rs]);
    }
    STn ask(int p, int l, int r, int x, int y){
        if (x <= l && r <= y) return a[p];
        push_down(p);
        if (y <= mid) return ask(ls, l, mid, x, y);
        if (x > mid) return ask(rs, mid + 1, r, x, y);
        return merge(ask(ls, l, mid, x, y), ask(rs, mid + 1, r, x, y));
    }
}tree;

signed main(){
    inv2 = q_powint(2, mod - 2);
    inv5 = q_powint(5, mod - 2);
    read(n, q);
    for (int i = 1; i <= n; i ++) read(inp[i]);
    tree.build(1, 1, n);
    while (q --) {
        read(op);
        if (op == 1) {
            read(in1, in2, in3);
            tree.change(1, 1, n, in1, in2, q_pow(Node{inv2, inv2}, in3), q_pow(Node{mod - inv2, inv2}, in3));
        }
        if (op == 2) {
            read(in1, in2);
            STn res = tree.ask(1, 1, n, in1, in2);
            Node res2 = frac(res.sum1 - res.sum2);
            int ans = res2.B;
            print(ans);
        }
    }
    return 0;
}

标签:Node,return,int,题解,sqrt,Sasha,res,Array,mod
From: https://www.cnblogs.com/TKXZ133/p/17803939.html

相关文章

  • 第四届辽宁省大学生程序设计竞赛部分题解
    2023辽宁省赛A:欢迎来到辽宁省赛题目描述小Z躺在床上看了看表,现在是13:30,2023辽宁省大学生程序设计竞赛的报名将会在14:00截止。然而不急,省赛的参赛队伍还没有向他提交名单。小Z知道,只要3分钟他就可以完成报名,完成汇款。现在他想知道,队伍要在多少分钟内......
  • [ABC326D] ABC Puzzle 题解
    题意:给定整数\(N\),字符串\(R,C\),构造满足以下条件的\(N\timesN\)矩阵:1.每一行和每一列中\(A,B,C\)各有且仅有一个。2.第\(i\)行的第一个字母等于字符串\(R\)的第\(i\)个字符。3.第\(i\)列的第一个字母等于字符串\(C\)的第\(i\)个字符。看数据范围考虑应该......
  • P4067 [SDOI2016] 储能表 题解
    [SDOI2016]储能表-洛谷题目详情-[SDOI2016]储能表-BZOJbyHydroOJ一道很好的数位dp题不过这题有一个比较有意思的性质:当\(n,m\)为\(2^k\)的形式时,最终得到的数组对每一行排序后为\(0\simm-1\)的排列,如果有的话说不定可以作为一个部分分?遇到二进制运......
  • 11月3号晚上测试题解
    3954ProblemA变量交换输出#include<stdio.h>intmain(){inta,b,c,x;scanf("%d%d%d",&a,&b,&c);//假设a,b,c分别为1,2,3;选择一个中间值进行数值替换x=a;//把a赋值给x,此时x就等于a的值为1a=c;//把c赋值给a,此时a就等于c的值为3c=b;//把b赋......
  • 详解Java ArrayList
    ArrayList简介ArrayList是List接口的实现类,底层基于数组实现,容量可根据需要动态增加,相当于动态数组。ArrayList继承于AbstractList,并且还实现了Cloneable、Serializable、RandomAccess接口。List:表明是列表数据结构,可以通过下标对元素进行添加删除或查找。Serializable:表示可......
  • CF1874F Jellyfish and OEIS 题解
    题目链接不明白出题人的脑回路是不是被宇宙射线改变过/jy。题目给出了若干个区间,要我们计算满足每个区间都不是对应下标的排列的数量,正着计算不满足要求的数量是困难的,我们将其容斥,转化为钦定一些区间要求其必须满足它是对应下标的排列,在下文中,我们称这样的区间为一个约束。我......
  • mybatis-plus的in,是传Array还是传List?仔细一看方法签名,瞬间秒懂
    springboot项目通常配合mybatisplus来做数据CRUD。我们在查询或更新数据的时候,有时要用到in来过滤数据。比如SELECT*FROMemax_scbg_orderWHEREorder_noIN(1305679009380433922,1305405259472830465)mybatisplus中关于in方法的使用,在传多个字段值的时候,我们经常搞不清是传Arr......
  • 题解 P6560 [SBCOI2020] 时光的流逝
    题解P6560[SBCOI2020]时光的流逝首先考虑图上的点为\(y\)终点时,或者这个点无法继续向下走,即\(du_i=0\)时,从这个点为起点先手必败,而对于每一个有一条指向先手必败的点的边的点,显然从这个点出发都是先手必胜的,以此类推。可以考虑建反图,进行拓扑排序,转移状态。#include<q......
  • 题解 [ARC149B] Two LIS Sum
    题解[ARC149B]TwoLISSum大胆猜结论,按照\(a\)数组为关键字进行排序,求更改后\(b\)的\(LIS\)。证明:每次移动,都有\(a\)中增加一个长度,\(b\)中贡献可能为\(\{-1,0,1\}\),总体贡献为\(\{0,1,2\}\),具体为:\(b\)中排序后大数变到小数前方。\(b\)中排序后小数仍然......
  • CF1872E Data Structures Fan 题解
    CF1872E翻译请把数据加强到\(\sumn\leq10^8\)后重新思考。我们维护全局中被标记的所有点的异或和。发现对于一次\(1\)操作,相当于让答案异或上区间的\(a_i\)异或和,因为这会让被标记的点变成没被标记的,而没被标记的点会产生贡献。查询的话直接查询即可复杂度......