题解 斐波
卡常题,O3+循环展开+测评姬波动卡过了
首先 \(g(i)=fib^2(i)\) 是可以矩阵乘的
接下来考虑题面里定义的 \(f\) 有什么性质
发现 \(f(S\cup{x})=\sum\limits_{s\in T}g(s)+\sum\limits_{s\in T}g(s+T)\)
就相当于乘上 \(I+tran^x\)
于是区间 \([l, r]\) 的答案可以表示成 \(g_0*\prod\limits_{i=l}^r(I+tran^{a_i})\)
这个东西可以线段树维护
但题面里问的是 \(\sum\limits_{i=l}^r\sum\limits_{j=i}^r f(l, r)\)
尝试分治
发现两个区间的信息是可以合并的
用一个四元组 \((tot, sum_{left}, sum_{right}, prod)\) 记录信息
tot为这个区间内的答案,prod为这个区间内 \(I+tran^x\) 的连乘积
sum_left为 \(\sum\limits_{i=l}^r f(i, r)\)
于是可以合并
然后就变成单点修改区间查询了
可以预处理tran的所有次方
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long
%:pragma GCC optimize(3)
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, q;
int a[N];
ll fib[N*20];
const int mod=998244353;
inline ll md(ll a) {return a>=mod?a-mod:a;}
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
namespace force{
int tem[N];
ll f(int l, int r) {
int len=r-l+1, lim=1<<len;
for (int i=l; i<=r; ++i) tem[i-l]=a[i];
ll ans=0; int sum;
for (int s=0; s<lim; ++s) {
sum=0;
for (int i=0; i<len; ++i) if (s&(1<<i)) sum+=tem[i];
ans=(ans+fib[sum]*fib[sum]%mod)%mod;
}
return ans;
}
void solve() {
fib[1]=1;
for (int i=2; i<N*20; ++i) fib[i]=md(fib[i-1]+fib[i-2]);
for (int i=1,p,v,l,r; i<=q; ++i) {
if (read()&1) {
p=read(); v=read();
a[p]=v;
}
else {
l=read(); r=read();
ll ans=0;
for (int j=l; j<=r; ++j) {
for (int k=j; k<=r; ++k) {
md(ans, f(j, k));
}
}
printf("%lld\n", ans);
}
}
exit(0);
}
}
namespace task{
struct matrix{
int n, m;
int a[3][3];
matrix(){memset(a, 0, sizeof(a)); n=m=0;}
matrix(int x, int y):n(x),m(y){memset(a, 0, sizeof(a));}
void resize(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));}
void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}}
inline int* operator [] (int t) {return a[t];}
inline matrix operator + (matrix b) {
matrix ans(n, m);
for (int i=0; i<n; ++i)
for (int j=0; j<m; ++j)
ans[i][j]=(a[i][j]+b[i][j])%mod;
return ans;
}
inline matrix operator * (matrix b) {
matrix ans(n, 3);
for (int i=0; i<n; ++i) {
ans[i][0]=(ans[i][0]+1ll*a[i][0]*b[0][0]+1ll*a[i][1]*b[1][0]+1ll*a[i][2]*b[2][0])%mod;
ans[i][1]=(ans[i][1]+1ll*a[i][0]*b[0][1]+1ll*a[i][1]*b[1][1]+1ll*a[i][2]*b[2][1])%mod;
ans[i][2]=(ans[i][2]+1ll*a[i][0]*b[0][2]+1ll*a[i][1]*b[1][2]+1ll*a[i][2]*b[2][2])%mod;
}
return ans;
}
}I, tran, g0, pw[N];
matrix qpow(matrix a, int b) {
if (!b) return I;
matrix ans=a; --b;
for (; b; a=a*a,b>>=1)
if (b&1) ans=ans*a;
return ans;
}
struct data{
matrix tot, sum1, sum2, prod;
data(){}
data(matrix a):tot(a),sum1(a),sum2(a),prod(a){}
data(matrix a, matrix b, matrix c, matrix d):tot(a),sum1(b),sum2(c),prod(d){}
inline void build(matrix a, matrix b, matrix c, matrix d) {tot=a; sum1=b; sum2=c; prod=d;}
inline void build(matrix a) {tot=sum1=sum2=prod=a;}
inline data operator + (data b) {
return data(tot+b.tot+sum1*b.sum2, sum1*b.prod+b.sum1, b.sum2*prod+sum2, prod*b.prod);
}
}dat[N<<2];
int tl[N<<2], tr[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define dat(p) dat[p]
#define pushup(p) dat(p)=dat(p<<1)+dat(p<<1|1)
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) {dat(p)=data(I+pw[a[l]]); return ;}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
}
void upd(int p, int pos, int val) {
if (tl(p)==tr(p)) {dat(p).build(I+pw[val]); return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, val);
else upd(p<<1|1, pos, val);
pushup(p);
}
data query(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) return dat(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid&&r>mid) return query(p<<1, l, r)+query(p<<1|1, l, r);
else if (l<=mid) return query(p<<1, l, r);
else return query(p<<1|1, l, r);
}
void solve() {
I.resize(3, 3); I[0][0]=I[1][1]=I[2][2]=1;
tran.resize(3, 3); tran[0][2]=-1; tran[1][0]=1; tran[1][2]=2; tran[2][1]=1; tran[2][2]=2;
g0.resize(1, 3); g0[0][1]=0; g0[0][1]=1; g0[0][2]=1;
pw[0]=I;
for (int i=1; i<N; ++i) pw[i]=pw[i-1]*tran;
build(1, 1, n);
for (int i=1,p,v,l,r; i<=q; ++i) {
if (read()&1) {
p=read(); v=read();
upd(1, p, v);
}
else {
l=read(); r=read();
printf("%d\n", ((g0*query(1, l, r).tot)[0][0]+mod)%mod);
}
}
exit(0);
}
}
signed main()
{
freopen("fib.in", "r", stdin);
freopen("fib.out", "w", stdout);
// cout<<double(sizeof(fib))/1024/1024<<endl;
n=read(); q=read();
for (int i=1; i<=n; ++i) a[i]=read();
// force::solve();
task::solve();
return 0;
}