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;
}