Codeforces 446C. DZY Loves Fibonacci Numbers【斐波那契+线段树】

C. DZY Loves Fibonacci Numbers

【题目描述】

传送门

【题解】

我们可以知道斐波那契数列有两个性质:

∑i=1nFi=Fn+2−F2\sum_{i=1}^{n} F_i=F_{n+2}-F_{2}i=1nFi=Fn+2F2

Fn=aF1+bF2F_n=aF_1+bF_2Fn=aF1+bF2

所以可以预先用矩阵乘法求出这个a和b,然后套线段树就可以了。

因为没模干净导致好几发WA,QAQ

【代码如下】

#include<cstdio>
using namespace std;
const int MAXN=300005,MOD=1e9+9;
int n,m,a[MAXN],Suma[MAXN],Tre[MAXN<<2];
void MO(int &x){x-=(x>=MOD?MOD:0);}
struct Matrix{
	int a[2][2];
	void INIT(){a[1][1]=a[1][0]=a[0][1]=1;a[0][0]=0;}
	Matrix operator *(const Matrix b)const{
		Matrix c;c.a[0][0]=c.a[1][0]=c.a[0][1]=c.a[1][1]=0;
		for(int i=0;i<2;i++)for(int j=0;j<2;j++)for(int k=0;k<2;k++) c.a[i][j]=(1ll*c.a[i][j]+1ll*a[i][k]*b.a[k][j])%MOD;
		return c;
	}
}Mul[MAXN];
struct FIB{
	int a[2];
	int z(){return a[0];}
	void clear(){a[0]=a[1]=0;}
	FIB operator *(const Matrix b)const{
		FIB c;c.a[0]=c.a[1]=0;
		c.a[0]=(1ll*a[0]*b.a[0][0]+1ll*a[1]*b.a[0][1])%MOD,c.a[1]=(1ll*a[0]*b.a[1][0]+1ll*a[1]*b.a[1][1])%MOD;
		return c;
	}
	FIB operator +(const FIB b)const{FIB c;MO(c.a[0]=a[0]+b.a[0]),MO(c.a[1]=a[1]+b.a[1]);return c;}
}Add[MAXN<<2];
FIB INIT(){FIB c;c.a[0]=0,c.a[1]=1;return c;}
int Sumfib(FIB f,int x){int z=(f*Mul[x+2]).z()-(f*Mul[2]).z();return z<0?z+MOD:z;}
int Sum(FIB x,int L,int R){int z=Sumfib(x,R)-Sumfib(x,L-1);return z<0?z+MOD:z;}
void PushDown(int rt,int L,int R){
	int mid=(R+L)>>1;
	MO(Tre[rt<<1]+=Sum(Add[rt],L-L+1,mid-L+1));Add[rt<<1]=Add[rt<<1]+Add[rt];
	MO(Tre[rt<<1|1]+=Sum(Add[rt],mid+1-L+1,R-L+1));Add[rt<<1|1]=Add[rt<<1|1]+(Add[rt]*Mul[mid+1-L]);
	Add[rt].clear();
}
void PushUp(int rt){MO(Tre[rt]=Tre[rt<<1]+Tre[rt<<1|1]);}
void Insert(int rt,int L,int R,int l,int r){
	if(l<=L&&R<=r){MO(Tre[rt]+=Sum((FIB){0,1},L-l+1,R-l+1));Add[rt]=Add[rt]+(INIT()*Mul[L-l]);return;}
	PushDown(rt,L,R);int mid=(R+L)>>1;
	if(l<=mid) Insert(rt<<1,L,mid,l,r);if(r>mid) Insert(rt<<1|1,mid+1,R,l,r);PushUp(rt);
}
int Query(int rt,int L,int R,int l,int r){
	if(l<=L&&R<=r) return Tre[rt];
	PushDown(rt,L,R);int mid=(R+L)>>1,Ans=0;
	if(l<=mid) MO(Ans+=Query(rt<<1,L,mid,l,r));if(r>mid) MO(Ans+=Query(rt<<1|1,mid+1,R,l,r));
	return Ans;
}
int main(){
	Mul[1].INIT();Mul[0].a[0][0]=Mul[0].a[1][1]=1;
	for(int i=2;i<300005;i++) Mul[i]=Mul[i-1]*Mul[1];
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),MO(Suma[i]=Suma[i-1]+a[i]);
	for(int i=1;i<=m;i++){
		int Type,L,R;scanf("%d%d%d",&Type,&L,&R);
		if(Type==1) Insert(1,1,n,L,R);else printf("%d\n",(Query(1,1,n,L,R)+(Suma[R]-Suma[L-1]+MOD)%MOD)%MOD);
	}
	return 0;
}

转载于:https://www.cnblogs.com/XSamsara/p/10547932.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值