博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
「LibreOJ NOI Round #2」单枪匹马
阅读量:5146 次
发布时间:2019-06-13

本文共 3327 字,大约阅读时间需要 11 分钟。

通过这道题成功发现我不会矩乘

答案是一个连分数,看起来不像是一般的数据结构能做的样子,设\(x_{l,r},y_{l,r}\)分别表示\([l,r]\)询问的分子和分母

于是有

\[\frac{x_{l,r}}{y_{l,r}}=a_{l}+\frac{y_{l+1,r}}{x_{l+1,r}}=\frac{y_{l+1,r}+a_l\times x_{l+1,r}}{x_{l+1,r}}\]

这么鬼畜的东西就应该写成矩阵的形式

于是

\[ \begin{bmatrix} a_l& 1\\ 1&0 \end{bmatrix}\times \begin{bmatrix} x_{l+1,r}\\ y_{l+1,r} \end{bmatrix}=\begin{bmatrix} y_{l+1,r}+a_l\times x_{l+1,r}\\ x_{l+1,r} \end{bmatrix}= \begin{bmatrix} x_{l,r}\\ y_{l,r} \end{bmatrix} \]

这是一个\(2\times 2\)的矩阵乘一个\(2\times 1\)的向量,所以必须是矩阵在前去乘向量其实我之前一直把向量写前面

于是对于\(l,r\)这样的一组询问我们要求的就是\(\begin{bmatrix} a_r\\ 1 \end{bmatrix}\)这样一个向量,去乘\(r-1\)\(l\)这些矩阵,而且必须是从\(r-1\)乘到\(l\),由于乘完一个矩阵得到的还是一个向量,所以向量还是放在后面,于是根据结合律前面就是从\(l\)乘到\(r-1\)

就是

\[ \begin{bmatrix} a_l& 1\\ 1&0 \end{bmatrix}\times \begin{bmatrix} a_{l+1}& 1\\ 1&0 \end{bmatrix}\times \begin{bmatrix} a_{l+2}& 1\\ 1&0 \end{bmatrix}\times ...\times \begin{bmatrix} a_{r-1}& 1\\ 1&0 \end{bmatrix}\times \begin{bmatrix} a_r\\ 1 \end{bmatrix} \]

于是我们需要查询一个区间内矩阵的乘积,数据范围\(10^6\),看起来不太好用带\(\log\)的东西维护,于是考虑强行求逆

\(2\times 2\)的逆矩阵手推一下就推出来了,就是\(\begin{bmatrix} 0& 1\\ 1&-a_{l} \end{bmatrix}\),于是我们再维护一个逆矩阵的前缀积就可以快速查询一个区间了

但是逆矩阵的前缀积需要维护从\(i\)乘到\(1\)的积,矩阵的前缀积需要维护从\(1\)\(i\)的积,查询的时候也是那逆矩阵的前缀积乘上矩阵前缀积,这样前面才能两两消掉

代码

#include
#define re register#define LL long long#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))inline int read() { char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;}const int maxn=1e6+5;const int mod=998244353;struct mat{int a[2][2];};inline int qm(int x) {return x>=mod?x-mod:x;}inline mat operator*(mat a,mat b) { mat c; c.a[0][0]=qm(1ll*a.a[0][0]*b.a[0][0]%mod+1ll*a.a[0][1]*b.a[1][0]%mod); c.a[0][1]=qm(1ll*a.a[0][0]*b.a[0][1]%mod+1ll*a.a[0][1]*b.a[1][1]%mod); c.a[1][0]=qm(1ll*a.a[1][0]*b.a[0][0]%mod+1ll*a.a[1][1]*b.a[1][0]%mod); c.a[1][1]=qm(1ll*a.a[1][0]*b.a[0][1]%mod+1ll*a.a[1][1]*b.a[1][1]%mod); return c;} inline void out(mat c) { printf("%d %d\n",c.a[0][0],c.a[0][1]); printf("%d %d\n",c.a[1][0],c.a[1][1]); puts("");}mat pre[maxn],inv[maxn];int n,m,type,a[maxn];int main() { n=read(),m=read(),type=read(); pre[0].a[0][0]=pre[0].a[1][1]=inv[0].a[0][0]=inv[0].a[1][1]=1; for(re int i=1;i<=n;i++) pre[i].a[0][1]=pre[i].a[1][0]=1; for(re int i=1;i<=n;i++) inv[i].a[0][1]=inv[i].a[1][0]=1; for(re int i=1;i<=n;i++) pre[i].a[0][0]=a[i]=read(),inv[i].a[1][1]=qm(mod-a[i]); for(re int i=1;i<=n;i++) pre[i]=pre[i-1]*pre[i],inv[i]=inv[i]*inv[i-1]; int lstx=0,lsty=0,op,x,l,r; while(m--) { op=read(); if(op==1) { x=read(); if(type) x^=(lstx^lsty);a[++n]=x; pre[n].a[0][1]=pre[n].a[1][0]=inv[n].a[0][1]=inv[n].a[1][0]=1; pre[n].a[0][0]=x,inv[n].a[1][1]=qm(mod-x); pre[n]=pre[n-1]*pre[n],inv[n]=inv[n]*inv[n-1]; } if(op==2) { l=read(),r=read(); if(type) l^=(lstx^lsty),r^=(lstx^lsty); if(l==r) lstx=a[l],lsty=1; else { mat c=inv[l-1]*pre[r-1]; lstx=qm(1ll*a[r]*c.a[0][0]%mod+c.a[0][1]); lsty=qm(1ll*a[r]*c.a[1][0]%mod+c.a[1][1]); } printf("%d %d\n",lstx,lsty); } } return 0;}

转载于:https://www.cnblogs.com/asuldb/p/11542312.html

你可能感兴趣的文章
leetcode-Sort List
查看>>
中文词频统计
查看>>
Postman-----如何导入和导出
查看>>
【Linux】ping命令详解
查看>>
Oracle中包的创建
查看>>
关于PHP会话:session和cookie
查看>>
jQuery on(),live(),trigger()
查看>>
treegrid.bootstrap使用说明
查看>>
[Docker]Docker拉取,上传镜像到Harbor仓库
查看>>
导航,头部,CSS基础
查看>>
[USACO 2017 Feb Gold] Tutorial
查看>>
gzip
查看>>
转负二进制(个人模版)
查看>>
LintCode-Backpack
查看>>
查询数据库锁
查看>>
我对于脚本程序的理解——百度轻应用有感
查看>>
面试时被问到的问题
查看>>
当前记录已被另一个用户锁定
查看>>
Node.js 连接 MySQL
查看>>
那些年,那些书
查看>>