题目链接
区间的数字和作为下标的斐波那契数
T = ∣ 1 1 1 0 ∣ \qquad\qquad\qquad\quad T=\begin{vmatrix}1&1\\1&0\end{vmatrix} T=∣∣∣∣1110∣∣∣∣
∴ f i b a + b = T a + b = T a ∗ T b = f i b a ∗ f i b b \therefore fib_{a+b}=T^{a+b}=T^a*T^b=fib_a*fib_b ∴fiba+b=Ta+b=Ta∗Tb=fiba∗fibb
区间的数字和作为下标的斐波那契数的平方
f i 2 = ( f i − 1 + f i − 2 ) 2 = f i − 1 2 + 2 f i − 1 f i − 2 + f i − 2 2 f_i^2=(f_{i-1}+f_{i-2})^2=f_{i-1}^2+2f_{i-1}f_{i-2}+f_{i-2}^2 fi2=(fi−1+fi−2)2=fi−12+2fi−1fi−2+fi−22
头尾两项好维护,关键是中间的二倍积
2 f i f i − 1 = 2 ( f i − 1 + f i − 2 ) f i − 1 = 2 f i − 1 2 + 2 f i − 1 f i − 2 2f_if_{i-1}=2(f_{i-1}+f_{i-2})f_{i-1}=2f_{i-1}^2+2f_{i-1}f_{i-2} 2fifi−1=2(fi−1+fi−2)fi−1=2fi−12+2fi−1fi−2
∴ [ f i 2 f i − 1 2 2 f i f i − 1 ] = [ 1 1 2 1 0 0 1 0 1 ] ∗ [ f i − 1 2 f i − 2 2 2 f i − 1 f i − 2 ] \therefore \begin{bmatrix}f_i^2\\f_{i-1}^2\\2f_if_{i-1}\end{bmatrix}=\begin{bmatrix}1&1&2\\1&0&0\\1&0&1\end{bmatrix}*\begin{bmatrix}f_{i-1}^2\\f_{i-2}^2\\2f_{i-1}f_{i-2}\end{bmatrix} ∴⎣⎡fi2fi−122fifi−1⎦⎤=⎣⎡111100201⎦⎤∗⎣⎡fi−12fi−222fi−1fi−2⎦⎤
集合的所有子集的数字作为下标的斐波那契数的平方和
容易发现 { { a } , { b } , { a , b } , ∅ } ⊆ { a , b } \{\{a\},\{b\},\{a,b\},\varnothing\}\subseteq\{a,b\} { { a},{ b},{ a,b},∅}⊆{ a,b}
⟹ ( a + 1 ) ( b + 1 ) = a + b + a b + 1 \Longrightarrow(a+1)(b+1)=a+b+ab+1 ⟹(a+1)(b+1)=a+b+ab+1
注意矩阵的1是
I = [ 1 0 0 0 1 0 0 0 1 ] I=\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix} I=⎣⎡100010001⎦⎤
区间的子区间的集合的所有子集的数字和作为下标的斐波那契数的平方和的和
用 m u l a \color{Red}mul_a mula记录区间 a a a内答案
m u l a = f i b a + I \color{Red}mul_a=fib_a+I mula=fiba+I
易得 m u l a + b = m u l a ∗ m u l b \color{Red}mul_{a+b}=mul_a*mul_b mula+b=mula∗mulb
用 p r e a \color{SkyBlue}pre_a prea记录 a a a的前缀的答案
则如图, p r e a + b = p r e a + m u l a ∗ p r e b \color{SkyBlue}pre_{a+b}=pre_a+mul_a*pre_b prea+b=prea+mula∗preb
同理,后缀答案 s u f a + b = s u f a ∗ m u l b + s u f b \color{RoyalBlue}suf_{a+b}=suf_a*mul_b+suf_b sufa+b=sufa∗mulb+sufb
所以总答案就是左边后缀拼右边前缀
a n s a + b = a n s a + a n s b + s u f a ∗ p r e b \color{LimeGreen}ans_{a+b}=ans_a+ans_b+suf_a*pre_b ansa+b=ansa+ansb+sufa∗preb
这些我们用线段树维护,单点修改区间查询
#include
#include
#define ls x<<1
#define rs x<<1|1
#define ll long long
const int N=1e5+10,M=3,mod=998244353;
int n,q,val[N];
inline ll add(ll a){
return a>mod?a-mod:a;}
struct Matrix{
ll a[M][M];};
Matrix one,fib[N];
inline Matrix operator+(const Matrix &x,const Matrix &y)
{
Matrix ret;
memset(ret.a,0,sizeof(ret.a));
for(int i=0;i<M;i++)
for(int j=0;j<M;j++)
ret.a[i][j]=add(x.a[i][j]+y.a[i][j]);
return ret;
}
inline Matrix operator*(const Matrix &x,const Matrix &y)
{
Matrix ret;
memset(ret.a,0,sizeof(ret.a));
for(int i=0;i<M;i++)
for(int k=0;k<M;k++)
if(x.a[i][k])
for(int j=0;j<M;j++)
ret.a[i][j]=add(ret.a[i][j]+x.a[i][k]*y.a[k][j]%mod);
return ret;
}
inline Matrix operator^(Matrix x,ll y)
{
Matrix ret=one;
while(y){
if(y&1)ret=ret*x;x=x*x,y>>=1;}
return ret;
}
struct Segment
{
int l,r;
Matrix mul,pre,suf,ans;
};
Segment T[N<<2];
inline Segment merge(const Segment &a,const Segment &b)
{
Segment ret;
ret.mul=a.mul*b.mul;
ret.pre=a.pre+a.mul*b.pre;
ret.suf=b.suf+b.mul*a.suf;
ret.ans=a.ans+b.ans+a.suf*b.pre;
return ret;
}
inline void build(int x,int l,int r)
{
T[x].l=l,T[x].r=r;
if(l==r){
T[x].ans=T[x].mul=T[x].pre=T[x].suf=fib[val[l]];return ;}
int m=l+r>>1;
build(ls,l,m),build(rs,m+1,r);
Segment s=T[x];
T[x]=merge(T[ls],T[rs]);
T[x].l=s.l,T[x].r=s.r;
}
inline void modify(int x,int k,int p)
{
if(T[x].l==k&&T[x].r==k){
T[x].ans=T[x].mul=T[x].pre=T[x].suf=fib[p];return ;}
int mid=T[x].l+T[x].r>>1;
if(k<=mid) modify(ls,k,p);
else modify(rs,k,p);
Segment s=T[x];
T[x]=merge(T[ls],T[rs]);
T[x].l=s.l,T[x].r=s.r;
}
inline Segment query(int x,int l,int r)
{
if(T[x].l==l&&T[x].r==r) return T[x];
int mid=T[x].l+T[x].r>>1;
if(r<=mid) return query(ls,l,r);
else if(l>mid) return query(rs,l,r);
return merge(query(ls,l,mid),query(rs,mid+1,r));
}
int main()
{
for(int i=0;i<M;i++) one.a[i][i]=1;
Matrix m1;
m1.a[0][0]=1;m1.a[0][1]=1;m1.a[0][2]=2;
m1.a[1][0]=1;m1.a[1][1]=0;m1.a[1][2]=0;
m1.a[2][0]=1;m1.a[2][1]=0;m1.a[2][2]=1;
fib[0]=one;
for(int i=1;i<N;i++) fib[i]=fib[i-1]*m1;
for(int i=1;i<N;i++) fib[i]=fib[i]+one;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",val+i);
build(1,1,n);
while(q--)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==1) modify(1,x,y);
else printf("%lld\n",query(1,x,y).ans.a[1][0]);
}
}