题解 P5110 【块速递推】
Description
题目链接:Luogu 5110
给定一个数列
求这个数列第
数据范围:
Solution
先考虑朴素的做法,我们可以直接用矩阵乘法和矩阵快速幂在
接下来我们考虑如何优化。由于
虽然有这样一个转化,但是我的复杂度瓶颈却在矩阵快速幂的
我们令矩阵
首先我们令
- 预处理
A^1,A^2,A^3,\cdots,A^k ,将矩阵A^i 记为X(i) 。 - 预处理
A^k,A^{2k},A^{2k},\cdots,A^{k^2} ,将矩阵A^{ik} 记为Y(i) 。
很显然以上两部分的复杂度均为
我们把询问
这样我们的询问复杂度就降低为
吐槽:此题卡常!出题人毒瘤!
时间复杂度:
Code
#include <cstdio>
#include <cstring>
const int N=32000,mod=1e9+7;
struct Matrix {
int mat[2][2];
Matrix operator * (const Matrix &b) const {
Matrix ans;
ans.mat[0][0]=(1LL*mat[0][0]*b.mat[0][0]+1LL*mat[0][1]*b.mat[1][0])%mod;
ans.mat[0][1]=(1LL*mat[0][0]*b.mat[0][1]+1LL*mat[0][1]*b.mat[1][1])%mod;
ans.mat[1][0]=(1LL*mat[1][0]*b.mat[0][0]+1LL*mat[1][1]*b.mat[1][0])%mod;
ans.mat[1][1]=(1LL*mat[1][0]*b.mat[0][1]+1LL*mat[1][1]*b.mat[1][1])%mod;
return ans;
}
} p1[N+5],p2[N+5];
unsigned long long SA,SB,SC;
unsigned long long rand() {
SA^=SA<<32,SA^=SA>>13,SA^=SA<<1;
unsigned long long t=SA;
SA=SB,SB=SC,SC^=t^SA;
return SC;
}
int main() {
Matrix s;
s.mat[0][0]=233,s.mat[0][1]=666,s.mat[1][0]=1,s.mat[1][1]=0;
p1[0].mat[0][0]=p1[0].mat[1][1]=1;
for(int i=1;i<=N;++i) p1[i]=p1[i-1]*s;
p2[0].mat[0][0]=p2[0].mat[1][1]=1,s=p1[N];
for(int i=1;i<=N;++i) p2[i]=p2[i-1]*s;
int T;
scanf("%d%llu%llu%llu",&T,&SA,&SB,&SC);
int ans=0;
for(int i=1;i<=T;++i) {
int n=(rand()-1)%(mod-1);
ans^=(p2[n/N]*p1[n%N]).mat[0][0];
}
printf("%d\n",ans);
return 0;
}