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

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

至于怎么解出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. autolayout 总结

    hasAmbiguousLayoutexerciseAmbiguityInLayout_autolayoutTracerecursiveDescription 第一步:更新约束,可以被认为是一个“计量 ...

  2. [原创]PostgreSQL中十进制、二进制、十六进制之间的相互转换

    在PostgreSQL中,二进制.十进制.十六进制之间的转换是非常方便的,如下: 十进制转十六进制和二进制 mydb=# SELECT to_hex(10); to_hex -------- a (1 ...

  3. ExtJS 提示

    要使ExtJS支持提示,需要在onReady的function中添加如下语句: Ext.QuickTips.init();//支持tips提示 Ext.form.Field.prototype.msg ...

  4. sharepoint 2010 基于AD的Form验证

    一.新建web应用程序 1.验证部分选择“基于声明的身份验证” 2.设置端口 3.选择“启用基于窗体的身份验证(FBA)” “ASP.NET 成员身份提供程序名称”下面填写“LdapMember” “ ...

  5. 003--VS2013 C++ 多边形绘制

    //全局变量HPEN hPen;HBRUSH hBru;POINT poly1[6], poly2[5], poly3[5]; //---------------------------------- ...

  6. Kinect帮助文档翻译之三 多场景

    在多个Sense中使用KinectManager 为了在多个场景下都能使用KinectManager这个组件,它必须被附在一个只生成一次.不会被销毁且在所有场景中都能访问的游戏物体上,显然把它附在Ma ...

  7. 将项目初始化到git服务器

    使用的是GitLab来管理Git服务器; 步骤: 一. 先在服务器上创建一个新的项目(GitLab右上角的New project)

  8. java中的匿名内部类总结(转)

    源出处: java中的匿名内部类总结 匿名内部类也就是没有名字的内部类 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接 ...

  9. Crawling is going on - Alpha版本测试报告

    [Crawling is going on - Alpha版本] 测 试 报 告 文件状态: [] 草稿 [√] 正式发布 [] 正在修改 报告编号: 当前版本: 1.0.2 编写人: 周萱.林谋武. ...

  10. 不同系统平台下Java默认的安装路径

    下面以Oracle的JDK7update 51为例: • 32-bit JDK on Windows: C:\Program Files (x86)\Java\jdk1.7.0_51 • 64-bit ...