HAUToj 1284: SP教数学 (线段树+矩阵快速幂

1284: SP教数学

Description

这里写图片描述

Input

这里写图片描述

Output

对于每组数据的2操作,输出一行对1e9 + 7取模的答案

Sample Input

7 4
2 2 1 1 3 3 2
2 1 5
2 6 7
1 3 4 3
2 6 6

Sample Output

6
3
2

题解:

//比赛全是原题 数据要不卡的难受 要不水的暴力能把2^50的复杂度跑过去 也是服气
不想费事安安心心拉VJ不好么TAT
线段树+矩阵快速幂

出题人的解释

我们知道对于斐波那契数可以通过乘以一个矩阵来进行递推。那么对于 +x 这一区间操作,我们可以对这一区间均乘以这个矩阵:

0 1
1 1 

​ 所以我们可以通过维护一棵线段树来完成这些,线段树上的每一个节点存储一个 1 x 2 的矩阵 [f(n-1),f(n)] 即可。为了快速计算某个 f(n) 的值,我们可以使用矩阵快速幂。
时间复杂度: O(mlogn + (n+m)logx)

下面有两个AC代码供参考
弱者的代码

AC代码

#include <bits/stdc++.h>
using namespace std;

#define LL long long


const int N = 100100;
const int mod = 1e9 + 7;
int n, m, c[N];
LL M[2][2] = {{0ll, 1ll}, {1ll, 1ll}}, V[2][2];
struct node{
    LL mat[2][2];
    LL lz[2][2];
    bool pu;
}t[N << 2];
#define lc x << 1
#define rc x << 1 | 1
void rset(LL a0[2][2]) { a0[0][0] = 1, a0[1][1] = 1, a0[1][0] = 0, a0[0][1] = 0;}
void mat_mul(LL a0[2][2], LL b0[2][2], LL ret[2][2])
{
    LL tmp[2][2];
    memset(tmp, 0, sizeof(tmp));
    for (int i = 0; i <= 1; i ++)
        for (int j = 0; j <= 1; j ++)
            for (int k = 0; k <= 1; k ++) tmp[i][j] = (tmp[i][j] + a0[i][k] * b0[k][j] % mod) % mod;
    for (int i = 0; i <= 1; i ++)
        for (int j = 0; j <= 1; j ++) ret[i][j] = tmp[i][j];
}
void mat_pow(LL a0[2][2], int k, LL ans[2][2])
{
    LL tmp[2][2];
    for (int i = 0; i <= 1; i ++)
        for (int j = 0; j <= 1; j ++) tmp[i][j] = a0[i][j];
    while(k){
        if (k & 1) mat_mul(ans, tmp, ans);
        mat_mul(tmp, tmp, tmp);
        k >>= 1;
    }
}
void up(int x){
    t[x].mat[0][0] = (t[lc].mat[0][0] + t[rc].mat[0][0]) % mod;
    t[x].mat[1][0] = (t[lc].mat[1][0] + t[rc].mat[1][0]) % mod;
}
void pushdown(int x)
{
    if (!t[x].pu) return ;
    t[lc].pu = true, t[rc].pu = true, t[x].pu = false;
    mat_mul(t[x].lz, t[lc].mat, t[lc].mat);
    mat_mul(t[x].lz, t[rc].mat, t[rc].mat);
    mat_mul(t[x].lz, t[lc].lz, t[lc].lz);
    mat_mul(t[x].lz, t[rc].lz, t[rc].lz);
    rset(t[x].lz);
}
void build(int x, int l, int r)
{
    rset(t[x].lz); rset(t[x].mat); t[x].pu = false;
    if (l == r){
        mat_pow(M, c[l] - 1, t[x].mat);
        t[x].mat[0][0] += t[x].mat[0][1], t[x].mat[0][0] %= mod;
        t[x].mat[1][0] += t[x].mat[1][1], t[x].mat[1][0] %= mod;
        return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid); build(rc, mid + 1, r); up(x);
}
void modify(int x, int l, int r, int a, int b)
{
    if (a <= l && r <= b){
        t[x].pu = true;
        mat_mul(t[x].lz, V, t[x].lz);
        mat_mul(V, t[x].mat, t[x].mat);
        return ;
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    if (a <= mid) modify(lc, l, mid, a, b);
    if (b > mid) modify(rc, mid + 1, r, a, b);
    up(x);
}
LL query(int x, int l, int r, int a, int b)
{
    if (a <= l && r <= b) return t[x].mat[0][0];
    pushdown(x);
    int mid = (l + r) >> 1;
    LL ret = 0;
    if (a <= mid) ret = (ret + query(lc, l, mid, a, b)) % mod;
    if (b > mid) ret = (ret + query(rc, mid + 1, r, a, b)) % mod;
    return ret;
}
int read(){
    int x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar(); }
    return x;
}
int main()
{
    n = read(), m = read();
    for (int i = 1; i <= n; i ++) c[i] = read();
    build(1, 1, n);
    int ty, l, r, v;
    for (int i = 1; i <= m; i ++){
        ty = read();
        if (ty == 1) {
            l = read(), r = read(), v = read();
            rset(V); mat_pow(M, v, V);
            modify(1, 1, n, l, r);
        }
        else {
            l = read(), r = read();
            printf("%d\n", query(1, 1, n, l, r));
        }
    }

    return 0;
}
出题人的标程
#include <bits/stdc++.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int MAXN = 1e5 + 10;

struct node {
    ll x, y;
}sum[MAXN << 2];

struct mat{
    ll p[3][3], sz;
    mat operator + (const mat &x) {
        mat tp; tp.sz = sz;
        for (int i = 1; i <= sz; i++)
            for (int j = 1; j <= sz; j++)
                tp.p[i][j] = (p[i][j] + x.p[i][j]) % MOD;
        return tp;
    }
    mat operator * (const mat &x) {
        mat tp; tp.sz = sz;
        for (int i = 1; i <= sz; i++)
            for (int j = 1; j <= sz; j++) {
                tp.p[i][j] = 0;
                for (int k = 1; k <= sz; k++)
                    tp.p[i][j] = (tp.p[i][j] + p[i][k] * x.p[k][j] % MOD) % MOD;
            }
        return tp;
    }
}unit, Am;

ll a[MAXN];
mat lazy[MAXN << 2];

mat pow_mod(mat a, ll n) {
    mat res = unit;
    while (n) {
        if (n & 1) res = res * a;
        a = a * a;
        n >>= 1;
    }
    return res;
}

void init() {
    memset(&unit, 0, sizeof(unit));
    memset(&Am, 0, sizeof(Am));
    unit.sz = Am.sz = 2;
    for (int i = 1; i <= 2; i++) unit.p[i][i] = 1;
    Am.p[1][1] = Am.p[1][2] = Am.p[2][1] = 1;
}

bool Is_unit(mat x) {
    if (x.p[1][1] || x.p[2][2]) return false;
    return true;
}

void push_up(int rt) {
    sum[rt].x = (sum[rt << 1].x + sum[rt << 1 | 1].x) % MOD;
    sum[rt].y = (sum[rt << 1].y + sum[rt << 1 | 1].y) % MOD;
}

void push_down(int rt) {
    ll x, y;
    if (!Is_unit(lazy[rt])) {
        lazy[rt << 1] = lazy[rt << 1] * lazy[rt];
        lazy[rt << 1 | 1] = lazy[rt << 1 | 1] * lazy[rt];
        x = (sum[rt << 1].x * lazy[rt].p[1][1] % MOD + sum[rt << 1].y * lazy[rt].p[1][2] % MOD) % MOD;
        y = (sum[rt << 1].x * lazy[rt].p[2][1] % MOD + sum[rt << 1].y * lazy[rt].p[2][2] % MOD) % MOD;
        sum[rt << 1] = (node){x, y};
        x = (sum[rt << 1 | 1].x * lazy[rt].p[1][1] % MOD + sum[rt << 1 | 1].y * lazy[rt].p[1][2] % MOD) % MOD;
        y = (sum[rt << 1 | 1].x * lazy[rt].p[2][1] % MOD + sum[rt << 1 | 1].y * lazy[rt].p[2][2] % MOD) % MOD;
        sum[rt << 1 | 1] = (node){x, y};
        lazy[rt] = unit;
    }
}

void build(int l, int r, int rt) {
    lazy[rt] = unit;
    if (l == r) {
        if (a[l] == 1) sum[rt] = (node) {1, 0};
        else if (a[l] == 2) sum[rt] = (node) {1, 1};
        else {
            mat tmp = pow_mod(Am, a[l] - 2);
            sum[rt].x = (1 * tmp.p[1][1] + 1 * tmp.p[1][2]) % MOD;
            sum[rt].y = (1 * tmp.p[2][1] + 1 * tmp.p[2][2]) % MOD;
        }
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    push_up(rt);
}

ll query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return sum[rt].x;
    push_down(rt);
    int m = (l + r) >> 1;
    ll res = 0;
    if (L <= m) res = (res + query(L, R, lson)) % MOD;
    if (R > m) res = (res + query(L, R, rson)) % MOD;
    return res;
}

void update(int L, int R, mat add, int l, int r, int rt) {
    if (L <= l && r <= R) {
        lazy[rt] = lazy[rt] * add;
        ll x = (sum[rt].x * add.p[1][1] % MOD + sum[rt].y * add.p[1][2] % MOD) % MOD;
        ll y = (sum[rt].x * add.p[2][1] % MOD + sum[rt].y * add.p[2][2] % MOD) % MOD;
        sum[rt] = (node){x, y};
        return;
    }
    push_down(rt);
    int m = (l + r) >> 1;
    if (L <= m) update(L, R, add, lson);
    if (R > m) update(L, R, add, rson);
    push_up(rt);
}

int main() {
    //freopen("in0.in", "r", stdin);
    init();
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build(1, n, 1);
    while (m--) {
        int op, l, r;
        ll x;
        scanf("%d", &op);
        if (op == 1) {
            scanf("%d%d%lld", &l, &r, &x);
            mat add = pow_mod(Am, x);
            update(l, r, add, 1, n, 1);
        }
        else {
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(l, r, 1, n, 1));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值