传送门
题意:
思路:只用矩阵快速幂会超时,加个记忆化就行了。
注意:tr1::unordered_map<ll, ll>mp 比 map<ll,ll> mp 要快很多,因为 tr1::unordered_map<ll, ll>mp 是用哈希实现的(头文件 #include <tr1/unordered_map> ),而map<ll,ll> mp 是用红黑树实现的。
/*
f(n)=3*f(n-1)+2*f(n-2);
构造二维矩阵
一:
求转置矩阵
f(n) f(n-1) f(n-1) f(n-2) 3 1
= *
( ) ( ) ( ) ( ) 2 0
求初始矩阵
f(n) f(n-1) 3 1
f(n-1) f(n-2) 1 1
此形势下 求值为 初始矩阵*转置矩阵
转置矩阵A 初始矩阵B
matrix a1,a2;
b1=qpow(A,n-2);
a1=multip(B,b1);注意这里一定要和上面对应
二:
求转置矩阵
f(n) ( ) 3 2 f(n-1) ( )
= *
f(n-1) ( ) 1 0 f(n-2) ( )
求初始矩阵
f(n) f(n-1) 3 1
f(n-1) f(n-2) 1 1
此形势下 求值为 转置矩阵*初始矩阵
转置矩阵A 初始矩阵B
matrix a1,a2;
b1=qpow(A,n-2);
a1=multip(b1,B);注意这里一二区别
*/
#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <cmath>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <tr1/unordered_map>
#include <algorithm>
#define ll long long
using namespace std;
const long long N=2;
const ll mod = 998244353;
tr1::unordered_map<ll,ll>mp;
struct matrix
{
long long a[N][N];
matrix()
{
memset(a,0,sizeof(a));
}
void init()
{
memset(a,0,sizeof(a));
for(long long i=0; i<N; i++)
{
a[i][i]=1;
}
}
};
matrix multip(matrix x,matrix y)
{
//相乘
matrix temp;
for(long long i=0; i<N; i++)
{
for(long long j=0; j<N; j++)
{
for(long long k=0; k<N; k++)
{
temp.a[i][j]=(temp.a[i][j]%mod+x.a[i][k]*y.a[k][j]%mod)%mod;
}
}
}
return temp;
}
matrix qpow(matrix M,long long k)
{
//矩阵快速幂
matrix temp;
temp.init();
while(k)
{
if(k&1)
{
temp=multip(temp,M);
}
k>>=1;
M=multip(M,M);
}
return temp;
}
int main()
{
ll n,q;
scanf("%lld%lld",&q,&n);
matrix A,B;
//转置矩阵
A.a[0][0]=3;
A.a[0][1]=1;
A.a[1][0]=2;
A.a[1][1]=0;
//初始矩阵
B.a[0][0]=3;
B.a[0][1]=1;
B.a[1][0]=1;
B.a[1][1]=0;
matrix a1,b1;
mp[0]=0;
mp[1]=1;
ll ans=0;
for(ll i=1; i<=q; i++)
{
if(mp.count(n)==0)
{
b1=qpow(A,n-2);
a1=multip(B,b1);
ans=ans^a1.a[0][0];
mp[n]=a1.a[0][0];
n=n^(a1.a[0][0]*a1.a[0][0]);
}
else
{
ans^=mp[n];
n^=(mp[n]*mp[n]);
}
}
printf("%lld\n",ans);
return 0;
}