HAUToj 1284: SP教数学 (线段树+矩阵快速幂
来源:互联网 发布:快递员扫码发短信软件 编辑:程序博客网 时间:2024/05/22 12:40
1284: SP教数学
Description
Input
Output
对于每组数据的2操作,输出一行对1e9 + 7取模的答案
Sample Input
7 42 2 1 1 3 3 22 1 52 6 71 3 4 32 6 6
Sample Output
632
题解:
//比赛全是原题 数据要不卡的难受 要不水的暴力能把2^50的复杂度跑过去 也是服气
不想费事安安心心拉VJ不好么TAT
线段树+矩阵快速幂
出题人的解释
我们知道对于斐波那契数可以通过乘以一个矩阵来进行递推。那么对于 +x 这一区间操作,我们可以对这一区间均乘以这个矩阵:
0 11 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 longconst 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 | 1void 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 | 1using 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;}
阅读全文
1 0
- HAUToj 1284: SP教数学 (线段树+矩阵快速幂
- 线段树+矩阵快速幂 codeforces718C Sasha and Array
- codeforces #373(div 2) E (线段树+矩阵快速幂)
- NOIP模拟题 [线段树][矩阵快速幂]
- [省选] [线段树] [矩阵快速幂] [HLOI2016] 序列问题
- CodeForces 575 A.Fibonotci(矩阵快速幂+线段树)
- hdu 6155 线段树加矩阵快速幂
- 2015 Multi-University Training Contest 3(hdu 5316、5317、5319、5323、5325、5326)线段树+数学+yy+矩阵快速幂
- 【矩阵乘法+快速幂】数学序列
- 【专题】—【数学】—【矩阵快速幂】
- 模板:(数学:矩阵快速幂)
- HDU 4565 (数学推导 矩阵快速幂)
- 【BZOJ2326】[HNOI2011]数学作业【矩阵快速幂】
- [BZOJ2326][HNOI2011]数学作业 矩阵快速幂
- 矩阵快速幂 [HNOI2011]数学作业
- 数学+矩阵快速幂 | 打表找规律+数学归纳
- UVA 1386 cellular automaton [循环矩阵+矩阵快速幂]【数学】
- Codeforces Round #373 (Div. 1)C(线段树维护矩阵,矩阵快速幂)
- mysql创建远程用户并授权
- SQL学习
- 什么是数据库,什么是SQL,什么是MySQL
- Spring-Bean的作用域
- C#学习过程中vs使用和代码编辑技巧总结
- HAUToj 1284: SP教数学 (线段树+矩阵快速幂
- linux下如何查看python位数
- Memcache的使用(c#)
- MySQL数据备份之mysqldump使用
- 如何把ubuntu的本地文件传到云端服务器(SSH)
- 读前辈的大话设计模式(九)之外观模式,抒自己的读后感
- 认证机构管理 - 认证业务范围分类表
- 百度网盘高速下载真实地址解析
- 认证机构管理 - 认证业务范围分类表