题目描述

卡德加喜欢养兔子。他在达拉然的下水道里放了 $N$ 个兔笼(编号从 $1$ 到 $N$),里面养着他从德拉诺带来的兔子。它们的繁殖遵循斐波那契数列的规律:刚开始时,笼子里有一对刚出生的兔子。每对兔子在出生第二个月后,每个月都生一对兔子。(第一个月结束后有 $1$ 对兔子。第二个月结束后有 $2$ 对。)

卡德加从苏拉玛的的大魔导师艾利桑德那边学习了先进的扭曲时空法术。有时候,他会对一排连续的兔笼(从第 $L$ 号到第 $R$ 号)释放时光流逝法术,让这些兔笼里的时间前进 $K$ 个月。另外一些时候,他想喂一下兔子,所以他想知道第 $L$ 号到第 $R$ 号兔笼里有多少只兔子。

(假设这些操作都是在一个月以内完成的,不需要考虑自然时间对兔子的影响。)

输入

第一行两个整数 $N,M$, 表示兔笼的数量和操作的数量。

接下来 $M$ 行,每行包含三个数 $L,R,K$。如果 $K > 0$,说明卡德加在使用时光流逝,编号 $L$ 到 $R$ 的兔笼时间前进 $K$ 个月。如果 $K = 0$,说明他只是想喂兔子了,输出这些兔笼里有多少兔子。

输出

对每个喂兔子的操作,输出兔子的数量。答案模 $10007$。

样例输入

10 10
1 3 2
1 1 0
2 4 0
3 5 0
4 7 3
3 5 0
1 4 0
2 7 0
1 9 4
2 10 0

样例输出

2
5
4
8
9
16
121

来源

2017 年 NOIP 夏令营

看到了询问区间,马上想到线段树;看到了斐波那契数列,马上想到矩阵快速幂。问题在于怎么结合了。

对于两个数列,如果这两个数列都具有斐波那契性质,则这两个数列的和也具有斐波那契性质。

什么意思呢?就是说对于两个数列 $\{x_1,x_2,x_3,x_4,\dots\}$,$\{y_1,y_2,y_3,y_4,\dots\}$,如果 $x_1+x_2=x_3, x_2+x_3=x_4, \dots, y_1+y_2=y_3, y_2+y_3=y_4, \dots$

如果有一个数列 $\{z_1,z_2,z_3,z_4,\dots\}$,其中 $z_1=x_1+y_1, z_2=x_2+y_2, \dots, z_k=x_k+y_k, \dots$

则有 $z_1+z_2=z_3, z_2+z_3=z_4, \dots$

这个不难证明,利用等式的性质就好了。

利用这个特性,我们可以在线段树的每个地方存储运算时的矩阵(因为满足分配率)。更新的时候,用矩阵加法就可以了。

另外,由 $\text{BSGS}$ 算法可知,此题还有一个优化:

斐波那契数列对 $10007$ 取模时,第 $1$ 个数与第 $20017$ 个数是一样的,第 $2$ 个数与第 $20018$ 个数是一样的。

这样就可以预先算好 $20017$ 个矩阵的值了,不需要使用快速幂。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; struct Matrix {
int mat[][];
Matrix() { memset(mat, , sizeof mat); }
}; const int MaxN = + ;
const int Mod = ; int N, M;
Matrix One, Fibo, Zero;
int L[MaxN * ], R[MaxN * ];
Matrix Sum[MaxN * ], Tag[MaxN * ]; inline Matrix operator + (Matrix A, Matrix B) {
Matrix C;
for (int i = ; i < ; ++i) for (int j = ; j < ; ++j)
C.mat[i][j] = (A.mat[i][j] + B.mat[i][j]) % Mod;
return C;
} inline Matrix operator * (Matrix A, Matrix B) {
Matrix C;
for (int i = ; i < ; ++i) for (int j = ; j < ; ++j) {
for (int k = ; k < ; ++k) C.mat[i][j] += A.mat[i][k] * B.mat[k][j] % Mod;
C.mat[i][j] %= Mod;
}
return C;
} inline Matrix operator ^ (Matrix low, int high) {
Matrix ans;
ans.mat[][] = ans.mat[][] = ;
while (high) {
if (high & ) ans = ans * low;
high >>= ;
low = low * low;
}
return ans;
} inline int read() {
int x = ; char c;
do c = getchar(); while (c < '' || c > '');
do x = (x << ) + (x << ) + c - '', c = getchar(); while (c >= '' && c <= '');
return x;
} inline void Push_up(int i) { Sum[i] = Sum[i << ] + Sum[i << | ]; } inline void Push_down(int i) {
int lson = i << , rson = i << | ; Tag[lson] = Tag[lson] * Tag[i];
Sum[lson] = Sum[lson] * Tag[i];
Tag[rson] = Tag[rson] * Tag[i];
Sum[rson] = Sum[rson] * Tag[i];
Tag[i] = One;
} void Build_Tree(int l, int r, int i) {
L[i] = l, R[i] = r;
Tag[i] = One;
if (l == r) {
Sum[i].mat[][] = Sum[i].mat[][] = ;
return;
}
int mid = L[i] + R[i] >> ;
Build_Tree(l, mid, i << );
Build_Tree(mid + , r, i << | );
Push_up(i);
} void Update_Tree(int l, int r, int k, int i) {
if (L[i] == l && R[i] == r) {
Sum[i] = Sum[i] * (Fibo ^ k);
Tag[i] = Tag[i] * (Fibo ^ k);
return;
}
Push_down(i); int mid = L[i] + R[i] >> ;
if (r <= mid) Update_Tree(l, r, k, i << );
else if (l > mid) Update_Tree(l, r, k, i << | );
else {
Update_Tree(l, mid, k, i << );
Update_Tree(mid + , r, k, i << | );
}
Push_up(i);
} Matrix Query_Tree(int l, int r, int i) {
if (L[i] == l && R[i] == r)
return Sum[i];
Push_down(i); int mid = L[i] + R[i] >> ;
if (r <= mid) return Query_Tree(l, r, i << );
else if (l > mid) return Query_Tree(l, r, i << | );
else {
Matrix lc = Query_Tree(l, mid, i << ), rc = Query_Tree(mid + , r, i << | );
return lc + rc;
}
} int main() {
N = read(); M = read();
One.mat[][] = One.mat[][] = ;
Fibo.mat[][] = Fibo.mat[][] = Fibo.mat[][] = ;
Build_Tree(, N, ); Matrix res;
for (int m = ; m <= M; ++m) {
int l, r, k;
l = read(); r = read(); k = read();
if (k == ) {
res = Query_Tree(l, r, );
printf("%d\n", res.mat[][]);
} else
Update_Tree(l, r, k, );
} return ;
}

FZOJ P2109 【卡德加的兔子】的更多相关文章

  1. BZOJ 1001: [BeiJing2006]狼抓兔子

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 20029  Solved: 4957[Submit][ ...

  2. JS循环语句作业讲解(折纸、兔子生兔子、买东西组合)

    1.一张纸的厚度是0.0001米,将纸对折,对折多少次厚度超过珠峰高度8848米: varn = 0;varg = 0.0001;while(){ g= g *2; n++ (g>8848bre ...

  3. bzoj 1001狼抓兔子(对偶图+最短路)最大流

    推荐文章:<浅析最大最小定理在信息学竞赛中的应用>--周冬 题目 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还 ...

  4. BZOJ1001: [BeiJing2006]狼抓兔子 [最小割 | 对偶图+spfa]

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 19528  Solved: 4818[Submit][ ...

  5. Java程序设计之裴波拉切那数列(兔子一年的数量)

    题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: 兔子的规律为数列1,1,2,3,5 ...

  6. [BZOJ4027][HEOI2015] 兔子与樱花

    Description 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接 ...

  7. js 斐波那契数列(兔子问题)

    对于JS初学者来说,斐波那契数列一直是个头疼的问题,总是理不清思路. 希望看完这篇文章之后会对你有帮助. 什么是斐波那契数列 : 答: 斐波那契数列,又称黄金分割数列.因数学家列昂纳多·斐波那契(Le ...

  8. Java经典兔子问题

    题目:古典问题:3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 分析:首先我们要明白题目的意思指的是每个月的兔子总对数:假设将兔子分为小 ...

  9. while做法1.兔子生兔子 2.求100以内质数的和3.洗发水15元 牙膏5元 香皂2元 150元的算法

    1.兔子生兔子 2.求100以内质数的和 3.150块钱花完问题

随机推荐

  1. 8 Oracle语句

    1.select name from v$datafile; 用sys方式登陆,查询所有表空间存放的物理路径 2.create tablespace DEMO_TBS datafile 'D:/TBS ...

  2. JACKSON详解

    Jackson 框架,轻易转换JSON Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 前面有介绍过json-lib这个框架,在 ...

  3. angularjs实例

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  4. H/s:哈希率单位转换

    哈系率说明 挖矿能力是通过寻找矿工可以执行的地块的尝试次数来衡量的.每次尝试都包括创建一个唯一的块候选项,并通过SHA-256d(一种加密哈希函数)创建块候选项的摘要.或者,简而言之,哈希.由于这是一 ...

  5. SpringBoot-将servlet容器变成undertow测试tomcat吞吐量

    将Servlet容器变成Undertow 默认情况下,Spring Boot 使用 Tomcat 来作为内嵌的 Servlet 容器 可以将 Web 服务器切换到 Undertow 来提高应用性能.U ...

  6. Python开发环境Linux配置

    1. 在Windows下安装Linux的连接工具(XShell),选免费的 2.虚拟机安装,注意BIOS对虚拟机使用的设置(enable) 3.虚拟机安装好修改yum源(用阿里云的):https:// ...

  7. python-浅拷贝和深拷贝

    浅拷贝和深拷贝 浅拷贝 拷贝的副本共享内部对象的引用的拷贝为浅拷贝 举个栗子 list1 = [1, 2, [3, 4], (5, 6)] list2= list(list1) print(" ...

  8. rosetta geometric constraint file(用于match和design)

    cst(constraint file)文件示例: CST::BEGIN TEMPLATE:: ATOM_MAP: atom_name: C6 O4 O2 TEMPLATE:: ATOM_MAP: r ...

  9. #WEB安全基础 : HTTP协议 | 0x3 TCP三次握手和DNS服务

    TCP三次握手精准无误地把数据送达目标处,TCP协议把数据包送出去后,向对方确认是否成功发送,握手过程中使用了TCP的标志(flag)——SYN和ACK 请看图 若握手中断,TCP协议再次从同样顺序发 ...

  10. js对象添加动态属性

    在业务中,经常会遇到使用同个方法调用多个同类型接口,以下简单模拟两个API接口 // api-1 { code: 0, status: 200, title: 'web前端框架', list: [ { ...