【LOJ573】「LibreOJ NOI Round #2」单枪匹马(矩阵乘法)

传送门


题解:

注意到分子分母每次无非就是交换位置然后分母加上分子的若干倍。

把这个转移写成矩阵的形式,求个逆,维护一下矩阵和矩阵的逆的前缀积就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num; 
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int mod=998244353;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}

struct mat{
	int a[2][2];
	int *operator[](int o){return a[o];}
	cs int *operator[](int o)cs{return a[o];}
	friend mat operator*(cs mat &A,cs mat &B){
		mat C;
		C[0][0]=add(mul(A[0][0],B[0][0]),mul(A[0][1],B[1][0]));
		C[0][1]=add(mul(A[0][0],B[0][1]),mul(A[0][1],B[1][1]));
		C[1][0]=add(mul(A[1][0],B[0][0]),mul(A[1][1],B[1][0]));
		C[1][1]=add(mul(A[1][0],B[0][1]),mul(A[1][1],B[1][1]));
		return C;
	}
};

inline mat get_inv(int a){return (mat){0,1,1,mod-a};}
inline mat get_mat(int a){return (mat){a,1,1,0};}

cs int N=1e6+7;
int n,m,ans,op;
mat pre[N],inv[N];

signed main(){
#ifdef zxyoi
	freopen("alone.in","r",stdin);
#endif
	n=gi(),m=gi(),op=gi();pre[0]=inv[0]=(mat){1,0,0,1};
	for(int re i=1;i<=n;++i){
		int a=gi();
		pre[i]=pre[i-1]*get_mat(a);
		inv[i]=get_inv(a)*inv[i-1];
	}
	while(m--){
		switch(gi()){
			case 1:{
				int a=gi();if(op)a^=ans;++n;
				pre[n]=pre[n-1]*get_mat(a);
				inv[n]=get_inv(a)*inv[n-1];
				break;
			}
			case 2:{
				int l=gi(),r=gi();if(op)l^=ans,r^=ans;
				mat res=inv[l-1]*pre[r]*(mat){1,0,0,0};
				cout<<res.a[0][0]<<" "<<res.a[1][0]<<"\n";
				ans=res.a[0][0]^res.a[1][0]; 
				break;
			}
		}
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值