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

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

至于怎么解出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 分块?)的更多相关文章

  1. ACM学习历程—Codeforces 446C DZY Loves Fibonacci Numbers(线段树 && 数论)

    Description In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence ...

  2. 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. ...

  3. Codeforces 446C DZY Loves Fibonacci Numbers [线段树,数论]

    洛谷 Codeforces 思路 这题知道结论就是水题,不知道就是神仙题-- 斐波那契数有这样一个性质:\(f_{n+m}=f_{n+1}f_m+f_{n}f_{m-1}\). 至于怎么证明嘛-- 即 ...

  4. CF446C DZY Loves Fibonacci Numbers 线段树 + 数学

    有两个性质需要知道: $1.$ 对于任意的 $f[i]=f[i-1]+f[i-2]$ 的数列,都有 $f[i]=fib[i-2]\times f[1]+fib[i-1]\times f[2]$ 其中 ...

  5. Codeforces446C - DZY Loves Fibonacci Numbers

    Portal Description 给出一个\(n(n\leq3\times10^5)\)个数的序列,进行\(m(m\leq3\times10^5)\)次操作,操作有两种: 给区间\([L,R]\) ...

  6. 『题解』Codeforces446C DZY Loves Fibonacci Numbers

    更好的阅读体验 Portal Portal1: Codeforces Portal2: Luogu Description In mathematical terms, the sequence \( ...

  7. codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)

    In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...

  8. Codeforces 446-C DZY Loves Fibonacci Numbers 同余 线段树 斐波那契数列

    C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...

  9. 【思维题 线段树】cf446C. DZY Loves Fibonacci Numbers

    我这种maintain写法好zz.考试时获得了40pts的RE好成绩 In mathematical terms, the sequence Fn of Fibonacci numbers is de ...

随机推荐

  1. 实战MySQL集群,试用CentOS 6下的MariaDB-Galera集成版

    说起mysql的集群估计很多人会首先想起mysql自带的replication或者mysql-mmm.mysql-mmm其实也是基于mysql自带的replication的,不过封装的更好用一些,但是 ...

  2. MySQL 的数值数据类型

    MySQL 的数值数据类型可以大致划分为两个类别,一个是整数,另一个是浮点数或小数.许多不同的子类型对这些类别中的每一个都是可用的,每个子类型支持不同大小的数据,并且 MySQL 允许我们指定数值字段 ...

  3. C语言中内存对齐方式

    一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...

  4. MongoDB复制机制实例

    MongoDB的主从复制是一个主可以多从已从又可以为主进行主从复制.在这里就是实现一主一从一个仲裁服务器使用一个数据库服务器通过提供不同的端口. 一.启动一个MongoDB服务名字是applicati ...

  5. System.IO之内存映射文件共享内存

    内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就 像操作进程空间里的地址一样了,比如使用c语言的memcpy等内存操作的函数.这种方法能够很好的应用在需要频繁处理一个 ...

  6. RTP、RTCP

    http://blog.chinaunix.net/uid-22670933-id-1771676.html

  7. func_num_args(),func_get_arg(),func_get_args()

    <?php function testFunction1(){ return func_num_args(); } function testFunction2(){ return func_g ...

  8. 第2章 变量和基本类型 附3---底层const和顶层const

    和英文版的对: As we’ve seen, a pointer is an object that can point to a different object. As a result,we c ...

  9. P1699: [Usaco2007 Jan]Balanced Lineup排队

    很明显是一道RMQ问题,倍增法,维护一下区域的最大/小值就行了. var n,i,j,q,f,t,times:longint; hmin,hmax:array[..,..] of longint; f ...

  10. net分布式系统架构

    net分布式系统架构的思路 最近看到有部分招聘信息,要求应聘者说一下分布式系统架构的思路.今天早晨正好有些时间,我也把我们实际在.net方面网站架构的演化路线整理一下,只是我自己的一些想法,欢迎大家批 ...