斐波
题目描述
题解
首先设\(f(S)=\sum_{T\subseteq S}g(\sum_{t\in T}t),g(n)=fib(n)^2\)
一个性质:
\(h(n)=f(n)*g(n)\),若\(f(n),g(n)\)都为线性递推式,则\(h(n)\)也为线性递推式
那么
\(fib(n)^2=[fib(n-1)+fib(n-2)]^2=fib(n-1)^2+fib(n-2)^2+2fib(n-1)fib(n-2)\)
\(2fib(n-1)fib(n-2)=fib(n-2)^2+fib(n-3)fib(n-2)+fib(n-1)[fib(n-1)-fib(n-3)]\)
\(\quad\quad\quad\quad\quad\quad\quad\quad\: =fib(n-2)^2+fib(n-1)^2+fib(n-3)fib(n-2)-fib(n-1)fib(n-3)\)
\(\quad\quad\quad\quad\quad\quad\quad\quad\: =fib(n-2)^2+fib(n-1)^2-fib(n-3)^2\)
则\(fib(n)^2=2fib(n-1)^2+2fib(n-2)^2-fib(n-3)^2\)
则\(g(n)=2g(n-1)+2g(n-2)-g(n-3)\)
则\(F(S)=\sum_{T\subseteq S}G(\sum_{t\in T}t)\)
考虑集合S新加个数{a}
则\(F(S \bigcup \{a\})=F(S)+\sum_{T\subseteq S}G(a+\sum_{t\in T}t)=(I+A^a)F(S)(I为单位矩阵)\)
因此\(F(S)=G(0)\cdot\prod_{s\in S}(I+A^s)\)
所以\(\sum_{i=l}^{r}\sum_{j=i}^{r}f(\{a_i,a_{i+1},···,a_j\})=G(0)\sum_{i=l}^{r}\sum_{j=i}^{r}\prod_{k=i}^j(I+A^{a_k})\)
这样就转化为了线段树的问题
首先考虑如何求\(T(l,r)=\sum_{i=l}^{r}\sum_{j=i}^{r}\prod_{k=i}^j(I+A^{a_k})\)
可以考虑分治的思想
先分别求出T(L,M)和T(M+1,R)
再求出贯穿M的区间答案
记\(S_l(l,r)=\sum_{i=l}^r\prod_{j=l}^i(I+A^{a_j}),S_r(i,j)=\sum_{i=l}^r\prod_{j=i}^r(I+A^{a_j})\)
则\(T(l,r)=T(l,M)+T(M+1,r)+S_r(l,M)*S_l(M+1,r)\)
设\(S_t(l,r)=\prod_{i=l}^r(I+A^{a_i})\)
则\(S_r(l,r)=S_r(M+1,r)+S_r(l,M)*S_t(M+1,r),S_l(l,r)=S_l(l,M)+S_l(M+1,r)*S_t(l,M),S_t(l,r)=S_t(l,M)*S_t(M+1,r)\)
那么我们可以用线段树,每个节点寸\(S_r,S_l,S_t,T\)的矩阵,合并的时候用上述式子即可
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long
using namespace std;
const int maxn=5e5+101;
const int MOD=998244353;
const int inf=2147483647;
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,m,a[maxn];
struct Matrix{
ll a[3][3];
void init(){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++)a[i][j]=(i==j);
}
}
void zero(){memset(a,0,sizeof(a));}
Matrix operator*(const Matrix& m2)const{
Matrix m;m.zero();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
(m.a[i][j]+=a[i][k]*m2.a[k][j]%MOD)%=MOD;
}
}
}
return m;
}
Matrix operator+(const Matrix& m2)const{
Matrix m;m.zero();
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
(m.a[i][j]+=(a[i][j]+m2.a[i][j])%MOD)%=MOD;
}
}
return m;
}
Matrix operator^(ll y)const{
Matrix sum,x;sum.init();
memcpy(x.a,a,sizeof(a));
while(y){
if(y&1)sum=sum*x;
y>>=1;x=x*x;
}
return sum;
}
}A,G;
struct tree{
Matrix M,sr,sl,st;
void init(){
M.init();sr.init();sl.init();st.init();
}
}tr[maxn];
void build(int k,int l,int r){
tr[k].init();
if(l==r){
Matrix ss;ss.init();
tr[k].M=tr[k].sr=tr[k].sl=tr[k].st=ss+(A^a[l]);//注意括号
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tr[k].M=(tr[k<<1].M+tr[k<<1|1].M)+(tr[k<<1].sr*tr[k<<1|1].sl);
tr[k].st=tr[k<<1].st*tr[k<<1|1].st;
tr[k].sl=tr[k<<1].sl+(tr[k<<1].st*tr[k<<1|1].sl);
tr[k].sr=tr[k<<1|1].sr+(tr[k<<1|1].st*tr[k<<1].sr);
return ;
}
void update(int k,int l,int r,int L,int R,int v){
if(r<L || l>R)return ;
if(L<=l && r<=R){
Matrix ss;ss.init();
tr[k].M=tr[k].sr=tr[k].sl=tr[k].st=ss+(A^v);
return ;
}
int mid=(l+r)>>1;
update(k<<1,l,mid,L,R,v);update(k<<1|1,mid+1,r,L,R,v);
tr[k].M=(tr[k<<1].M+tr[k<<1|1].M)+(tr[k<<1].sr*tr[k<<1|1].sl);
tr[k].st=tr[k<<1].st*tr[k<<1|1].st;
tr[k].sl=tr[k<<1].sl+(tr[k<<1].st*tr[k<<1|1].sl);
tr[k].sr=tr[k<<1|1].sr+(tr[k<<1|1].st*tr[k<<1].sr);
return ;
}
Matrix query(int k,int l,int r,int L,int R,bool &fa,Matrix &s1,Matrix &s2,Matrix &s3){
Matrix ss;ss.zero();
if(r<L || l>R){
fa=0;
return ss;
}
if(L<=l && r<=R){
fa=1;
s1=tr[k].sl;s2=tr[k].sr;s3=tr[k].st;
return tr[k].M;
}
int mid=(l+r)>>1;
Matrix sl1,sl2,sl3;
Matrix sr1,sr2,sr3;
Matrix aans;
bool fa1=0,fa2=0;
Matrix ans1=query(k<<1,l,mid,L,R,fa1,sl1,sl2,sl3);
Matrix ans2=query(k<<1|1,mid+1,r,L,R,fa2,sr1,sr2,sr3);
aans=ans1+ans2;
if(fa1 && fa2){
fa=1;
aans=aans+(sl2*sr1);
s1=sl1+(sl3*sr1);
s2=sr2+(sr3*sl2);
s3=sl3*sr3;
}
else if(fa1){
fa=1;
s1=sl1;s2=sl2;s3=sl3;
}
else {
fa=1;
s1=sr1;s2=sr2;s3=sr3;
}
return aans;
}
int main(){
A.a[0][0]=A.a[0][1]=2;A.a[0][2]=-1;
A.a[1][0]=1;A.a[1][1]=A.a[1][2]=0;
A.a[2][0]=A.a[2][2]=0;A.a[2][1]=1;
G.a[0][0]=0;G.a[1][0]=G.a[2][0]=1;
n=read();m=read();for(int i=1;i<=n;i++)a[i]=read();build(1,1,n);
for(int i=1;i<=m;i++){
int opt=read(),l=read(),r=read();
if(opt==1)update(1,1,n,l,l,r);
else {
bool fa;
Matrix s1,s2,st,ss=query(1,1,n,l,r,fa,s1,s2,st);ss=ss*G;
printf("%lld\n",(ss.a[0][0]%MOD+MOD)%MOD);
}
}
return 0;
}