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

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

至于怎么解出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. 菜鸟学习Hibernate——一对多关系映射

    Hibernate中的关系映射,最常见的关系映射之一就是一对多关系映射例如学生与班级的关系,一个班级对应多个学生.如图: Hibernate中如何来映射这两个的关系呢? 下面就为大家讲解一下: 1.创 ...

  2. StyleCop学习笔记——自定义规则

    本文将简单的一步一步的指导这可能有助于学习如何创建自己的规则 1.创建一个项目. Visual Studio创建一个新的类库项目.NET3.5 2.引用两个DLL,StyleCop.dll和Style ...

  3. hdu 1973 Prime Path

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1973 Prime Path Description The ministers of the cabi ...

  4. hdu 2822 Dogs

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2822 Dogs Description Prairie dog comes again! Someda ...

  5. 【EF Code First】CodeFirst初始配置

    1,在Nuget管理中下载EntityFramework 2,配置文件中添加数据库配置 <connectionStrings> <add name="DefaultConn ...

  6. 使用Ajax.BeginForm 中需要 上传文件 但 Request.files获取不到

    使用Mvc里的插件jquery.unobtrusive-ajax.min.js 之前一直困在这里,一开始以为添加属性enctype="multipart/form-data"就可以 ...

  7. Matlab实现均匀量化

    Matlab实现均匀量化 首先读入一个音频文件的前200个点,如果音频通道大于1则只取一个通道,滤掉其余的 得到音频文件的最大值和最小值,最大值和最小值的差除以2的4次方即16得到量化电平的端点间隔. ...

  8. 用Sqlplus手动创建Oracle11g数据库

    用Sqlplus手动创建Oracle数据库 刚开始学习Oracle数据库,菜鸟一个,使用sqlplus创建数据库遇到了很多问题,通过不断地百度,终于创建成功了.所以顺便把整个过程中犯的一些最低级的错误 ...

  9. win7无线网卡的灯突然不亮了的解决办法

    win7无线网卡的灯突然不亮了,百度了一下,按如下的方法解决了:  WIN7中:右键单击“计算机”,选择“管理”进入“计算机管理”,选择“服务和运用”下的“服务”,然后双击“WLAN AutoConf ...

  10. java无符号移位(>>>)和有符号移位(>>)

    java中>>(<<)表示有符号的移位.<<<(>>>)表示无符号移位 如: int num = 22; 二进制是0001 0110, nu ...