Codeforces446C DZY Loves Fibonacci Numbers(线段树 or 分块?)

第一次看到段更斐波那契数列的,整个人都不会好了。事后看了题解才明白了一些。

首先利用二次剩余的知识,以及一些数列递推式子有下面的

至于怎么解出x^2==5(mod 10^9+9),我就不知道了,但是要用的时候可以枚举一下,把这些参数求出来之后就题目就可以转化为维护等比数列。

由于前面的常数可以最后乘,所以就等于维护两个等比数列好了。

下面我们来看如何维护一个等比数列。假如我对区间[L,R]的加上1,2,4,8...2^n的话,那么我只需要加一个标记x表示这个区间被加了多少次这样的2^n.

举个例子  [1,8] 上加一个等比数列,我只需要x+=1,就可以了,当我的区间往下传的时候,[1,4]这个区间的x+=1,[5,8]这个区间x+=2^4*1

这个利用的就是公比相同的数列相加仍然是等比数列的性质。求和利用的则是 a1(q^n-1)/(q-1),所以只需要预处理出q-1的逆元还有q^n我们就可以根据区间信息很快的求出和了。

在本题中 q-1的逆=q,首项也是q,所以前n项和就是 qi^(n+2)-qi^2(i=1,2). 其实主要就是考虑怎么维护等比数列的问题。

然后我看到在别人的AC的方法里还有这么一种神方法,他预先设定了一个阈值K,当当前的更新操作数j<K的时候,它就用一个类似于树状数组段更的方法,用一个 d数组去存内容,譬如它要在区间 [3,6]上加一段fibonacci

原来:

id 0 1 2 3 4 5 6 7 8 9 10

d  0 0 0 0 0 0 0 0 0 0 0

更新:

id 0 1 2 3 4 5 6  7  8  9 10

d  0 0 0 1 0 0 0 -5  -3 0 0

我们可以发现,当利用 d[i]=d[i]+d[i-1]+d[i-2] i由小到大更新后就会得到

id 0 1 2 3 4 5 6  7  8  9 10

d  0 0 0 1 1 2 3  0  0  0  0

所以对于[L,R]上加一段操作,我们可以d[L]+=1; d[R+1]-=f[R-L+2],d[R+2]=f[R-L+1];

所以假如我更新了m次,我每次更新的复杂度是O(1),我把所有数求出来一次的复杂度是O(n)

然后他的算法是这样的,j<K的时候更新的时候按照上述方法更新,询问的话则是将询问区间和更新的区间求交,把交的和加上去。

当j==K的时候,利用d还原出新的a,把当前的区间清0.

不难发现,复杂度应该为O(mn/K+mK),当mn/K=mK的时候取最小值,所以复杂度是O(mn^(1/2)).

然后由于CF可以承受10 ^8的运算,所以打个擦边球AC了。下面贴两份代码:

#pragma warning(disable:4996)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;

#define ll long long
#define mod 1000000009
#define maxn 300500
ll bas = 276601605;
ll q1 = 691504013;
ll q2 = 308495997;

ll xx5 = 383008016;
ll inv5 = 200000002;
ll inv2 = 500000005;

ll invq1;
ll invq2;

ll pow_mod(ll a, ll n){
	ll ret = 1;
	while (n){
		if (n & 1) ret = ret*a%mod;
		n >>= 1;
		a = a*a%mod;
	}
	return ret;
}

ll a[maxn], b[maxn];
int n, m;

ll val[maxn];
ll sum[maxn];

struct Node
{
	int l, r;
	ll ax, bx;
	ll sum;
}N[maxn << 2];

void build(int i, int L, int R){
	N[i].l = L; N[i].r = R;
	N[i].ax = N[i].bx = N[i].sum = 0;
	if (L == R){
		return;
	}
	int M = (L + R) >> 1;
	build(i << 1, L, M);
	build(i << 1 | 1, M + 1, R);
}

void pushDown(int i){
	ll av = N[i].ax, bv = N[i].bx;
	if (N[i].ax != 0 || N[i].bx != 0){
		N[i << 1].ax = (N[i << 1].ax + av) % mod;
		N[i << 1].bx = (N[i << 1].bx + bv) % mod;
		int len = N[i << 1].r - N[i << 1].l + 1;
		N[i << 1 | 1].ax = (N[i << 1 | 1].ax + av*a[len] % mod) % mod;
		N[i << 1 | 1].bx = (N[i << 1 | 1].bx + bv*b[len] % mod) % mod;
		int len2 = N[i << 1 | 1].r - N[i << 1 | 1].l + 1;
		N[i << 1].sum = (N[i << 1].sum + av*(((a[len + 2] - a[2]) % mod + mod) % mod) % mod) % mod;
		N[i << 1].sum = (N[i << 1].sum - bv*(((b[len + 2] - b[2]) % mod + mod) % mod) % mod) % mod;
		N[i << 1 | 1].sum = (N[i << 1 | 1].sum + av*a[len] % mod*(a[len2 + 2] - a[2] + mod) % mod) % mod;
		N[i << 1 | 1].sum = ((N[i << 1 | 1].sum - bv*b[len] % mod*(b[len2 + 2] - b[2] + mod) % mod) % mod + mod) % mod;
		N[i].ax = N[i].bx = 0;
	}
}

void pushUp(int i){
	N[i].sum = (N[i << 1].sum + N[i << 1 | 1].sum) % mod;
}

void update(int i, int L, int R, ll x, ll y){
	if (N[i].l == L&&N[i].r == R){
		N[i].ax = (N[i].ax + x) % mod;
		N[i].bx = (N[i].bx + y) % mod;
		int len = R - L + 1;
		N[i].sum = (N[i].sum + x*(a[len + 2] - a[2] + mod) % mod + mod) % mod;
		N[i].sum = (N[i].sum - y*(b[len + 2] - b[2] + mod) % mod + mod) % mod;
		return;
	}
	pushDown(i);
	int M = (N[i].l + N[i].r) >> 1;
	if (R <= M){
		update(i << 1, L, R, x, y);
	}
	else if (L > M){
		update(i << 1 | 1, L, R, x, y);
	}
	else{
		int len = (M - L + 1);
		update(i << 1, L, M, x, y);
		update(i << 1 | 1, M + 1, R, a[len] * x%mod, b[len] * y%mod);
	}
	pushUp(i);
}

ll query(int i, int L, int R){
	if (N[i].l == L&&N[i].r == R){
		return N[i].sum;
	}
	pushDown(i);
	int M = (N[i].l + N[i].r) >> 1;
	if (R <= M){
		return query(i << 1, L, R);
	}
	else if (L > M){
		return query(i << 1 | 1, L, R);
	}
	else{
		return (query(i << 1, L, M) + query(i << 1 | 1, M + 1, R)) % mod;
	}
	pushUp(i);
}

int main()
{
	scanf("%d%d", &n, &m);
	a[0] = b[0] = 1;
	for (int i = 1; i <= n + 5; i++){
		a[i] = a[i - 1] * q1%mod;
		b[i] = b[i - 1] * q2%mod;
	}
	val[0] = 0; sum[0] = 0;
	for (int i = 1; i <= n; i++){
		scanf("%I64d", val + i);
		sum[i] = (sum[i - 1] + val[i]) % mod;
	}
	build(1, 1, n);
	int oper, l, r;
	for (int i = 0; i < m; i++){
		scanf("%d%d%d", &oper, &l, &r);
		if (oper == 1) update(1, l, r, 1, 1);
		else {
			ll res = query(1, l, r);
			res = (res + mod) % mod;
			res = res*bas%mod;
			res = (res + ((sum[r] - sum[l - 1]) % mod+mod)%mod) % mod;
			printf("%I64d\n", res);
		}
	}
	return 0;
}
#pragma warning(disable:4996)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
#include <queue>
using namespace std;

#define ll long long
#define maxn 310000
#define K 800
#define mod 1000000009

ll a[maxn];
ll s[maxn];
ll f[maxn], g[maxn];
int n, m;
int kk;
ll d[maxn];

int l[K + 50], r[K + 50];

int main()
{
    while (cin >> n >> m)
    {
        f[0] = 0; f[1] = 1; g[0] = 0; g[1] = 1;
        for (int i = 2; i <= n+10; i++){
            f[i] = (f[i - 1] + f[i - 2]) % mod;
            g[i] = (g[i - 1] + f[i]) % mod;
        }
        s[0] = 0;
        for (int i = 1; i <= n; i++){
            scanf("%I64d", &a[i]);
            s[i] = (s[i - 1] + a[i]) % mod;
        }
        memset(d, 0, sizeof(d));
        int oper, li, ri;
        kk = 0;
        for (int i = 0; i < m; i++){
            scanf("%d%d%d", &oper,&li,&ri);
            if (oper == 1){
                l[kk] = li, r[kk] = ri;
                d[li] = (d[li] + 1) % mod;
                d[ri + 1] = ((d[ri + 1] - f[ri - li + 2]) % mod + mod) % mod;
                d[ri + 2] = ((d[ri + 2] - f[ri - li + 1]) % mod + mod) % mod;
                kk++;
                if (kk == K){
                    for (int i = 1; i <= n; i++){
                        if (i == 1) a[i] = (a[i] + d[i]) % mod;
                        else {
                            d[i] = (d[i] + d[i - 1] + d[i - 2]) % mod;
                            a[i] = (a[i] + d[i]) % mod;
                        }
                        s[i] = (s[i - 1] + a[i]) % mod;
                    }
                    memset(d, 0, sizeof(d));
                    kk = 0;
                }
            }
            else{
                ll res = ((s[ri] - s[li - 1]) % mod + mod) % mod;
                for (int j = 0; j < kk; j++){
                    int lb = max(l[j], li);
                    int rb = min(r[j], ri);
                    if (lb <= rb){
                        res = (res + (g[rb - l[j] + 1] - g[lb - l[j]]) % mod + mod) % mod;
                    }
                }
                printf("%I64d\n", res);
            }
        }
    }
    return 0;
}

Codeforces446C DZY Loves Fibonacci Numbers(线段树 or 分块?)

时间: 2024-11-03 01:35:34

Codeforces446C DZY Loves Fibonacci Numbers(线段树 or 分块?)的相关文章

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. f[n] 是斐波那契数列 也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少 通过简单的公式叠加也能求和 F[n]  = f[n - 1] * b + f[n - 2] * a F[n - 1] = f[n - 2] * b + f[n - 3] * a ..

CF446C DZY Loves Fibonacci Numbers 线段树 + 数学

code: #include <bits/stdc++.h> #define N 400004 #define LL long long #define lson now<<1 #define rson now<<1|1 #define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace

Codeforces446C - DZY Loves Fibonacci Numbers

Portal Description 给出一个\(n(n\leq3\times10^5)\)个数的序列,进行\(m(m\leq3\times10^5)\)次操作,操作有两种: 给区间\([L,R]\)加上一个斐波那契数列,即\(\{a_L,a_{L+1},...,a_R\} \rightarrow \{a_L+F_1,a_{L+1}+F_2,...,a_R+F_{R-L+1}\}\) 询问区间\([L,R]\)的和,对\(10^9+9\)取模. 斐波那契数列:\(F_1=1,F_2=2\)且满足

codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)

In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 = 1; F2 = 1; Fn = Fn - 1 + Fn - 2 (n > 2). DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: a1, a2, ...,

codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新

DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-14) Description In mathematical terms, the sequence Fn of Fibonacci numbers is defi

[CodeForces - 447E] E - DZY Loves Fibonacci Numbers

E  DZY Loves Fibonacci Numbers In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1?=?1; F2?=?1; Fn?=?Fn?-?1?+?Fn?-?2 (n?>?2). DZY loves Fibonacci numbers very much. Today DZY gives you an array consist

Codeforces 444C DZY Loves Colors 水线段树

题目链接:点击打开链接 水.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set> #include <vector> #include <map> using namespace std; #define ll long long #defi

Codeforces Round #FF (Div. 2) E. DZY Loves Fibonacci Numbers(斐波那契的定理+线段树)

/* 充分利用了菲波那切数列的两条定理: ①定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[n] = b * fib[n - 1] + a * fib[n - 2](n≥3),其中fib[i]为斐波那契数列的第 i 项. ②定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[1] + F[2] + -- + F[n] = F[n + 2] - b 这题还有一个事实,

【CF446C】DZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)

Description ? 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solution ? 先来考虑一段斐波那契数列如何快速求和,根据性质有 \[ \begin {align} fib_n &= fib_{n - 1} + fib_{n - 2} \ &= fib_ {n - 2} + fib_{n - 3} + fib_{n - 2} \ &= fib_{n -