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

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

至于怎么解出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. 《高性能javascript》读书笔记

    1.每个<script>加载时都会阻塞其他文件(图片.音乐等)的同时加载,同时浏览器会在js代码执行时停止渲染Dom.所以为了减少界面加载的卡顿和空白发生,应尽力将js代码或者文件放在&l ...

  2. 值类型和引用类型(C#基础知识复习)

    一.值类型和引用类型 二.值类型的赋值和相等 三.引用类型的赋值和同一

  3. C#调用sap接口及返回数据到sap

    public class SapClass { /// <summary> /// /// </summary> /// <param name="fphm&q ...

  4. oracle 11g 修改默认监听端口1521

    OS: Oracle Linux Server release 5.7 DB: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - ...

  5. 九度oj 1521 二叉树的镜像

    原题链接:http://ac.jobdu.com/problem.php?pid=1521 水题,如下.. #include<algorithm> #include<iostream ...

  6. iOS学习之UI自定义cell

    一.自定义Cell 为什么需要自定义cell:系统提供的cell满足不了复杂的样式,因此:自定义Cell和自定义视图一样,自己创建一种符合我们需求的Cell并使用这个Cell.如下图所示的这些Cell ...

  7. matlab 函数的编写与调用

    matlab中写个函数,在主程序中调用该函数的方法 跟其它的编程语言都一样,但是子函数与主函数要存于不同的文件中,文件名就是函数名字.文件必须保存在current directory中,才能调用. 函 ...

  8. 子网划分与CIDR(斜杠加数字的表示与IP 的关系)(改进)

    子网和CIDR   将常规的子网掩码转换为二进制,将发现子网掩格式为连续的二进制1跟连续0,其中子网掩码中为1的部份表示网络ID,子网掩中为0的表示主机ID.比如255.255.0.0转换为二进制为1 ...

  9. js之Function原型

    在ECMAScript中,Function(函数)类型实际上是对象.每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.由于函数是对象,因此函数名实际上也是一个指向函数对象 ...

  10. 【原创】只用 HTML / CSS 画出一把 UKULELE(夏威夷四弦吉他)

    在线演示:http://abelyao.github.io/ukulele/  源代码: https://github.com/AbelYao/css-ukulele  效果图:   为了熟练 CSS ...