题目描述

卡德加喜欢养兔子。他在达拉然的下水道里放了 $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. 微信小程序时间戳的转换及调用

    13位 的时间戳,如下图: 效果图: 1.(utils.js里面的代码): function formatTime(timestamp, format) { const formateArr = [' ...

  2. shell符号

    *:  通配符 *.c : c结尾的文件 *v : v结尾的文件 v* : v开头的文件

  3. Linux 下挂载新硬盘方法

    Linux的硬盘识别: 一般使用”fdisk -l”命令可以列出系统中当前连接的硬盘 设备和分区信息.新硬盘没有分区信息,则只显示硬盘大小信息.   1.关闭服务器加上新硬盘   2.启动服务器,以r ...

  4. vue的数据双向绑定和ref获取dom节点

    vue是一个MVVM的框架 业务逻辑代码即js部分是model部分, html是view部分. 当model改变的时候,view也会改变 view 改变是,model也会改变 <template ...

  5. C++11 vector使用emplace_back代替push_back

    C++11中,针对顺序容器(如vector.deque.list),新标准引入了三个新成员:emplace_front.emplace和emplace_back,这些操作构造而不是拷贝元素.这些操作分 ...

  6. FastJson一些常见方法(API):处理JSON变得好简单

    fastjson是目前java语言中最快的json库,比自称最快的jackson速度要快,第三方独立测试结果说明比gson快大约6倍 JSON帮助类 这个可以做一个实例研究代码,也可以作为一个工具类 ...

  7. 洛谷P2569 股票交易 [SCOI2010] dp

    正解:dp+单调队列优化 解题报告: 先放个传送门鸭qwq umm首先dp转移挺好想的?就买和不买 f[i][j]表示第i天手上有j的股份的最多钱,转移也很好想?就枚举第1天到第i-w-1天枚举买k股 ...

  8. Django配置相关及其它

    配置 模板 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.pat ...

  9. IO实时监控命令iostat详解

    iostat用于输出CPU和磁盘I/O相关的统计信息 命令格式 iostat [ -c ] [ -d ] [ -h ] [ -N ] [ -k | -m ] [ -t ] [ -V ] [ -x ] ...

  10. css设置input获得焦点的样式

    input:focus{ 样式; } 这样就ok