这道题题意很简单;但是如果你用struct矩阵快速幂就是t,我就是QAQ;最后自己手写了两个函数来搞快速幂,然后才AC的;
因为我发现如果用结构体的话,那么就会调用复制构造函数,这样时间复杂度就上升了;
现在说说这道题的意思吧:
题意:就是上面那个等式,很明显如果以前有经验的一看就是矩阵快速幂:
可以很明显的构造出一个矩阵出来:
然后就可以知道它:
如果你不清楚为什么是n-1的话,你可以这样想一想;
如果n取3;那么就是:
所以可以推出来指数为n-1;
然后就很简单了直接矩阵快速幂就OK了;
但是你会发现t了?why????
其实比赛的时候我也不知道为啥;但是赛后我才知道因为n是异或的值,所以可能异或到以前出现过的值,如果以前出现过n了,那么我就不需要计算了吧;所以我就可以用一个map来标记是否算过以n-1为指数的矩阵快速幂;就不用再去算了,所以可以自己手写三个函数去实现快速幂;那么最后答案就是Fn=a[0][0]*F1+a[0][1]*F0;可以知道F0=0所以就没必要写后面的了;就直接:
Fn=a[0][0]*F1;
所以这道题就AC了,说实话这个题也是比较坑的,1.重复出现,2.结构体快速幂有复制构造函数所以就不能用struct去写;
以后吸取教训了,快速幂最好都自己去手写一遍,免得t了;
常识补充其实map还可以用unordered_map来标记,只不过这里没用到查找功能,所以一个简单的map就够了;
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Mod=998244353;
#define N 2//这里表示2*2的矩阵//如果是3*3的 则可以令为N 3
map<ll,ll> A;
ll a[N][N],one[N][N],t[N][N];//a是初始化矩阵,one是单位矩阵,t是临时矩阵
void Multiply(ll b[N][N],ll c[N][N]){//求两个矩阵相乘存在b中 ,因为二维数组传的是首地址,所以实参会被修改
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
t[i][j]=0;
}
}
for(ll i=0;i<N;i++){
for(ll j=0;j<N;j++){
for(ll k=0;k<N;k++)
{
t[i][j]=(t[i][j]+b[i][k]*c[k][j])%Mod;//算两个矩阵的乘法
}
}
}
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
b[i][j]=t[i][j];//复制给b
}
}
}
void QP(ll x[N][N],ll n)//答案存在单位矩阵中
{
while(n){
if(n&1){
Multiply(one,x);
}
Multiply(x,x);
n>>=1;
}
}
void init(){//初始化构造矩阵+单位矩阵
a[0][0]=3;a[0][1]=2;a[1][0]=1;//初始化矩阵
a[1][1]=0;
one[1][0]=one[0][1]=0;
for(int i=0;i<2;i++)one[i][i]=1;//初始化单位矩阵
}
int main(){
ios::sync_with_stdio(false);//关闭同步
ll f1=1;
ll Q,n,ans=0;
cin>>Q>>n;
while(Q--){
if(A[n]){//检查是否以n-1为幂是否计算过了
ans^=A[n];
}else{
init();
QP(a,n-1);
A[n]=one[0][0]*f1;
ans^=A[n];
n=n^(A[n]*A[n]);
}
}
prinf("%lld",ans);//输出答案
return 0;
}