[CF718C] Sasha and Array
Description
给定一个数列,维护两种操作
操作 \(1\),将区间 \([l,r]\) 的数字统一加 \(x\)。
操作 \(2\),求 \(\sum \limits_{i=l}^r f(val[i])\),其中 \(f(i)\) 表示斐波那契数列的第 \(i\) 项。‘
答案对 \(10^9+7\) 取模。
Solution
线段树维护矩阵。
因为是斐波那契数列,容易想到用矩阵快速幂来求这个东西。
想这样做的话,要想清楚两个问题:
- 因为题目中求的是和,那么知道 \([l,mid]\) 和\([mid+1,r]\) 的答案能否快速合并出 \([l,r]\) 的答案呢?
- 如果知道了 \([l,r]\) 的答案,对于区间加 \(x\) 操作,能否快速得知操作后的答案呢?
对于第一个问题,由于矩阵具有分配律,即 \(a\times b+a\times c=a\times(b+c)\),所以对于一段区间的矩阵可以相加维护。
对于第二个问题,显然将 \([l,r]\) 的矩阵乘上转移矩阵的 \(x\) 次方即可。
综上,两个问题想清楚之后,我们用线段树来维护区间中的矩阵。
Code
// By YoungNeal
#include<cstdio>
#include<cctype>
#define N 100005
#define int long long
const int mod=1e9+7;
int n,m;
int val[N];
struct Matrix{
int m[4][4];
void clear(){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++)
m[i][j]=0;
}
}
void init(){
for(int i=0;i<4;i++)
m[i][i]=1;
}
void print(){
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++)
printf("i=%I64d,j=%I64d,m=%I64d\n",i,j,m[i][j]);
}
}
bool empty(){
if(m[1][1]!=1) return 0;
if(m[1][2]!=0) return 0;
if(m[2][1]!=0) return 0;
if(m[2][2]!=1) return 0;
return 1;
}
Matrix operator*(const Matrix &y) const {
Matrix z; z.clear();
for(int i=1;i<=2;i++){
for(int k=1;k<=2;k++){
for(int j=1;j<=2;j++)
z.m[i][j]=(z.m[i][j]+m[i][k]*y.m[k][j])%mod;
}
}
return z;
}
friend Matrix operator+(Matrix a,Matrix b){
Matrix c;c.clear();
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++)
c.m[i][j]=(a.m[i][j]+b.m[i][j])%mod;
}
return c;
}
};
Matrix dw,fir;
Matrix mat[N<<2],lazy[N<<2];
int getint(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
Matrix ksm(Matrix a,int b){
Matrix ret; ret.clear(); ret.init();
while(b){
if(b&1) ret=ret*a;
a=a*a;
b>>=1;
}
return ret;
}
void pushup(int cur){
mat[cur]=mat[cur<<1]+mat[cur<<1|1];
}
void build(int cur,int l,int r){
mat[cur].clear();
lazy[cur].clear();
lazy[cur].init();
if(l==r){
mat[cur]=fir*ksm(dw,val[l]-1);
return;
}
int mid=l+r>>1;
build(cur<<1,l,mid);
build(cur<<1|1,mid+1,r);
pushup(cur);
}
void pushdown(int cur,int l,int r){
if(lazy[cur].empty()) return;
mat[cur<<1]=mat[cur<<1]*lazy[cur];
lazy[cur<<1]=lazy[cur<<1]*lazy[cur];
mat[cur<<1|1]=mat[cur<<1|1]*lazy[cur];
lazy[cur<<1|1]=lazy[cur<<1|1]*lazy[cur];
lazy[cur].clear();
lazy[cur].init();
}
void modify(int cur,int ql,int qr,int l,int r,Matrix x){
if(ql<=l and r<=qr){
mat[cur]=mat[cur]*x;
lazy[cur]=lazy[cur]*x;
return;
}
pushdown(cur,l,r);
int mid=l+r>>1;
if(ql<=mid)
modify(cur<<1,ql,qr,l,mid,x);
if(mid<qr)
modify(cur<<1|1,ql,qr,mid+1,r,x);
pushup(cur);
}
Matrix query(int cur,int ql,int qr,int l,int r){
if(ql<=l and r<=qr)
return mat[cur];
pushdown(cur,l,r);
Matrix ret;ret.clear();
int mid=l+r>>1;
if(ql<=mid)
ret=ret+query(cur<<1,ql,qr,l,mid);
if(mid<qr)
ret=ret+query(cur<<1|1,ql,qr,mid+1,r);
return ret;
}
signed main(){
dw.clear(); fir.clear();
dw.m[1][1]=1;fir.m[1][1]=1;
dw.m[1][2]=1;fir.m[1][2]=1;
dw.m[2][1]=1;fir.m[2][1]=0;
dw.m[2][2]=0;fir.m[2][2]=0;
n=getint(),m=getint();
for(int i=1;i<=n;i++)
val[i]=getint();
build(1,1,n);
while(m--){
if(getint()==1){
int l=getint(),r=getint(),x=getint();
modify(1,l,r,1,n,ksm(dw,x));
}
else{
int l=getint(),r=getint();
printf("%I64d\n",query(1,l,r,1,n).m[1][2]%mod);
}
}
return 0;
}
[CF718C] Sasha and Array的更多相关文章
- 【题解】[CF718C Sasha and Array]
[题解]CF718C Sasha and Array 对于我这种喜欢写结构体封装起来的选手这道题真是太对胃了\(hhh\) 一句话题解:直接开一颗线段树的矩阵然后暴力维护还要卡卡常数 我们来把\(2 ...
- CF718C Sasha and Array 线段树+矩阵加速
正解:线段树 解题报告: 传送门! 首先这种斐波拉契,又到了1e9的范围,又是求和什么的,自然而然要想到矩阵加速昂 然后这里主要是考虑修改操作,ai+=x如果放到矩阵加速中是什么意思呢QAQ? 那不就 ...
- CF718C Sasha and Array(线段树维护矩阵)
题解 (不会矩阵加速的先去学矩阵加速) 反正我想不到线段树维护矩阵.我太菜了. 我们在线段树上维护一个区间的斐波那契的列矩阵的和. 然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个 ...
- CF718C Sasha and Array 线段树 + 矩阵乘法
有两个操作: 将 $[l,r]$所有数 + $x$ 求 $\sum_{i=l}^{r}fib(i)$ $n=m=10^5$ 直接求不好求,改成矩阵乘法的形式: $a_{i}=M^x\times ...
- CF718C Sasha and Array [线段树+矩阵]
我们考虑线性代数上面的矩阵知识 啊呸,是基础数学 斐波那契的矩阵就不讲了 定义矩阵 \(f_x\) 是第 \(x\) 项的斐波那契矩阵 因为 \(f_i * f_j = f_{i+j}\) 然后又因为 ...
- 【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法
C. Sasha and Array time limit per test:5 seconds memory limit per test:256 megabytes input:standard ...
- codeforces 719E E. Sasha and Array(线段树)
题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...
- Sasha and Array
Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input standard inp ...
- 【codeforces 718 C&D】C. Sasha and Array&D. Andrew and Chemistry
C. Sasha and Array 题目大意&题目链接: http://codeforces.com/problemset/problem/718/C 长度为n的正整数数列,有m次操作,$o ...
随机推荐
- DB2 键约束操作
DB2 键约束操作 今天遇到一个问题,想要删掉一个表中的某列的唯一约束,google了一下,搜出来许许多多,找到能用的,记下来总结如下. 命令如下 select constname, tabname, ...
- httpd安装与配置(编译安装)
httpd简介 httpd是Apache超文本传输协议(HTTP)服务器的主程序.被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程的池. 通常,httpd不应该被直接调用,而应该在类 ...
- Linux环境下java开发环境搭建二 tomcat搭建
第一步:下载安装包并解压 # tar zxvf 压缩包名 第二步:把解压出的文件移动到/usr/local/tomcat7中 #mv 解压出来的文件夹 /usr/local/tomcat7 第三步: ...
- 网站日志流量分析采集(LuaJIT系统环境部署-node03,相关jar包自己手动上传)
注:/usr/local/src 是源码包路径,可以自己更改 服务器中安装依赖 yum -y install gcc perl pcre-devel openssl openssl-devel 上传 ...
- sqlserver数据库创建快照发布遇到的错误:对路径“XXXX”访问被拒绝
在创建了一个sqlserver数据库的发布后,显示创建成功,但当查看快照代理状态时,显示“对路径‘XXXX’访问被拒绝”,这一错误导致订阅无法实现.然后网上有一方案帮忙解决了,主要有以下操作: 1)在 ...
- Linux命令之tee - 重定向输出到多个文件
http://codingstandards.iteye.com/blog/833695 tee 将标准输出复制一份 ls -al | tee -a tmpls.log ls -al >> ...
- 2-postman批量执行接口
1.postman环境设置与使用 1)点击设置,添加按钮 2)填写环境名称,参数 3)切换环境 4)使用环境变量,使用格式为:{{变量名}} 2.postman批量执行接口 1)选择要执行的文件夹,点 ...
- redis知识点杂记
最近梳理了一下redis的基本知识.本文会从redis的简单使用.redis的数据类型.redis持久化三个方面做简单阐述和总结. 一.Redis基本操作 1.key的规则 不能使用\n空格.其他都可 ...
- 开发微信小程序——古龙小说阅读器
概述 由于面试的关系接触了一下微信小程序,花了2晚上开发了一个带书签功能的古龙小说阅读器,并且已经提交审核等待发布.这篇博文记录了我的开发过程和对微信小程序的看法,供以后开发时参考,相信对其他人也有用 ...
- 手把手教你如何用eclipse搭建前端开发环境
3.创建静态web工程 打开eclipse,选择file,new project 或者 new other...,选择web项中的static web project ,next. 输入你的项目名,如 ...