您的位置:首页 > 其它

CodeForces 446C DZY Loves Fibonacci Numbers(线段树+数论)

2017-08-11 17:15 537 查看
题意:给出一个序列,现在有两种操作,第一种是修改操作,将某个区间加上斐波那契数列的一段,第二种是查询操作,查询某个区间的区间和。

思路:这道题要解决的问题就是斐波那契数列的段更新操作。

首先写出斐波那契数列的通项公式



我们可以把平方根换成模同余的整数

首先可以暴力跑出5的平方剩余,也就是说



 然后把上式中的非整数用模同余的整数替代







所以原式现在变成了



也就是说现在的问题是维护一段等比数列,这一步可以用线段树来做,方法是记录当前区间和以及当前区间有几个q,q^2,q^3.....q^(r-l+1)的标记

注意到等比数列求和的时候用到了公式

q(q^n-1)/(q-1)而本题中q-1的逆元是q,所以求和公式简化为

q^(n+2)-q^2

#include <bits/stdc++.h>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#define pb push_back
#define mp make_pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 1500000;
const int MOD = 1e9+9;
LL bas = 276601605;
LL q1 = 691504013;
LL q2 = 308495997;
LL mul1[MAXN], mul2[MAXN];
int c[MAXN];
LL s[MAXN];

struct Node {
LL a, b, sum;
} node[MAXN];
int n, k;

void init(int m) {
mul1[0] = mul2[0] = 1;
for (int i = 1; i <= m; i++) {
mul1[i] = mul1[i-1] * q1 % MOD;
mul2[i] = mul2[i-1] * q2 % MOD;
}
}
void build(int o, int l, int r) {
node[o].a = node[o].b = node[o].sum = 0;
if (l == r) return;
int m = (l+r) >> 1;
build(o<<1, l, m);
build((o<<1)+1, m+1, r);
}
void push_down(int o, int l, int r) {
LL aa = node[o].a, bb = node[o].b;
if (!aa && !bb) return;
int lc = o << 1, rc = (o<<1)|1, mid = (l+r) >> 1;
int len1 = mid-l+1, len2 = r - mid;

node[lc].a = (node[lc].a+aa) % MOD;
node[lc].b = (node[lc].b+bb) % MOD;
node[lc].sum = (node[lc].sum+aa*(mul1[len1+2]-mul1[2])) % MOD;
node[lc].sum = (node[lc].sum-bb*(mul2[len1+2]-mul2[2])) % MOD;

node[rc].a = (node[rc].a+aa*mul1[len1]) % MOD;
node[rc].b = (node[rc].b+bb*mul2[len1]) % MOD;
node[rc].sum = (node[rc].sum + aa*mul1[len1]%MOD*(mul1[len2+2]-mul1[2])%MOD) % MOD;
node[rc].sum = (node[rc].sum - bb*mul2[len1]%MOD*(mul2[len2+2]-mul2[2])%MOD) % MOD;

node[o].a = node[o].b = 0;
}
void push_up(int o) {
node[o].sum = (node[o<<1].sum+node[(o<<1)|1].sum) % MOD;
}
LL query(int o, int l, int r, int ql, int qr) {
if (l == ql && r == qr)
return node[o].sum;
push_down(o, l, r);
int mid = (l+r) >> 1;
if (qr <= mid)
return query(o<<1, l, mid, ql, qr);
else if (ql > mid)
return query((o<<1)|1, mid+1, r, ql, qr);
else
return (query(o<<1, l, mid, ql, mid)+query((o<<1)|1, mid+1, r, mid+1, qr)) % MOD;
}
void update(int o, int l, int r, int ql, int qr, LL x, LL y) {
if (l == ql && r == qr) {
node[o].a = (node[o].a+x) % MOD;
node[o].b = (node[o].b+y) % MOD;
node[o].sum = (node[o].sum+x*(mul1[r-l+3]-mul1[2])) % MOD;
node[o].sum = (node[o].sum-y*(mul2[r-l+3]-mul2[2])) % MOD;
return;
}
push_down(o, l, r);
int mid = (l+r) >> 1;
if (qr <= mid)
update(o<<1, l, mid, ql, qr, x, y);
else if (ql > mid)
update((o<<1)|1, mid+1, r, ql, qr, x, y);
else {
int len = mid - ql + 1;
update(o<<1, l, mid, ql, mid, x, y);
update((o<<1)|1, mid+1, r, mid+1, qr, x*mul1[len]%MOD, y*mul2[len]%MOD);
}
push_up(o);
}

int main()
{
//freopen("input.txt", "r", stdin);
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
s[i] = s[i-1] + c[i];
}
init(301000);
build(1, 1, n);
for (int i = 1; i <= k; i++) {
int op, l, r;
scanf("%d%d%d", &op, &l, &r);
if (op == 1)
update(1, 1, n, l, r, 1, 1);
else {
LL ans = (bas*query(1, 1, n, l, r)%MOD+s[r]-s[l-1]) % MOD;
if (ans < 0) ans += MOD;
printf("%I64d\n", ans);
}
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: