题解 斐波

传送门

卡常题,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;
}
posted @ 2021-10-25 20:56  Administrator-09  阅读(2)  评论(0编辑  收藏  举报