支持后面加数,区间进行奇怪的要求操作算值。
你看这个操作是个线性的迭代,这种时候就应该想到线性代数,那就想到矩阵。
你就强行用矩阵表示,然后手玩一下结果矩阵来反推原来的矩阵。
手玩出来每个数的初始矩阵是
0 1
1 a[i]
其中右下角是分子,右上角是分母。
正确性?找两个矩阵乘起来就正确了。
那么一个区间可以视作1到r的矩阵乘去掉1到l-1。
这个去掉操作联想乘逆元,所以乘矩阵逆元前缀积就行。
一个矩阵的逆元无非就是两者乘起来为单位矩阵。
那一个初始矩阵的逆元就是
-a[i] 1
1 0
为什么?还是手玩啊。
然后我们来看这个gcd的问题。gcd和取模是不能共生的。
但是!
这道题很nb的在于它欺骗了你,因为任何时候分子分母都是互质的。
从最开始两个整数一个倒过来加上去再加1肯定是互质的。就算你是1也可以把分母去掉。
其次,假设一个最简分数加上一个整数,那肯定还是互质的啊。要不然早就约了。
所以大胆地取模就是了。
小细节:注意,矩阵不满足交换律,所以逆元矩阵的前缀积处理要和原来矩阵前缀积反着来。这样两者中间相遇的才是对应的矩阵。
// 好自闭啊这个题,,草稿打的头都秃了。
// 甚至暴力只能从右往左迭代,还不能往右扩展,莫队都没法。
// 想到最后只能求助于矩阵。
// 这是一个固定的变换格式,只要我能用矩阵表示出来我就赢了
// 发现卧槽还真能表示出来。
// 然后被gcd和取模的问题卡了很久很久
// 最后发现不对啊,一个最简分数加上一个整数好像还是最简分数吧
// 那我为啥不直接膜呢。
// 就完了,,那个gcd真tm唬人
// 小细节:卡了我半小时,,因为矩阵没有交换律,,手玩了几个发现前缀积的处理还要注意顺序,,
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
struct node{
int a[3][3];
};
const int mod=998244353;
node operator *(node a,node b){
node ans;memset(ans.a,0,sizeof(ans.a));
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
for(int k=1;k<=2;k++){
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;;
}
}
}return ans;
}int n,m,type,lastx,lasty;
node fac[1000003],ifac[1000003];
node prefac[1000003],preifac[1000003];
int a[1000003];
void insert(int i,int x){
fac[i].a[1][2]=fac[i].a[2][1]=1;fac[i].a[2][2]=x;
ifac[i].a[1][1]=mod-x;ifac[i].a[2][1]=ifac[i].a[1][2]=1;
prefac[i]=prefac[i-1]*fac[i];
preifac[i]=ifac[i]*preifac[i-1];
}
node fzone,fmone;
int Gcd(int x,int y){
if(!y)return x;
return Gcd(y,x%y);
}
signed main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=in;m=in;type=in;prefac[0].a[1][1]=prefac[0].a[2][2]=preifac[0].a[1][1]=preifac[0].a[2][2]=1;
for(int i=1;i<=n;i++){
a[i]=in;insert(i,a[i]);
}int op,x,y;
while(m--){
op=in;x=in;if(type)x=x^lastx^lasty;
if(op==1){
a[++n]=x;insert(n,a[n]);
}else{
y=in;if(type)y=y^lastx^lasty;
//cout<<x<<" "<<y<<"@# "<<endl;
//cout<<prefac[y].a[2][2]<<" "<<prefac[y].a[2][1]<<"@# 3#"<<endl;;
node ans=preifac[x-1]*prefac[y];
int fm=ans.a[1][2],fz=ans.a[2][2];
// int gcd=Gcd(fz,fm);
// lastx=fz/gcd;lasty=fm/gcd;
lastx=fz,lasty=fm;
printf("%lld %lld\n",lastx,lasty);
}
}
return 0;
}