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

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

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

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

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

首先可以暴力跑出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;
}

















  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值