题解
比赛时我还没解完,就被用矩阵快速幂加map过掉了。。但还是补上这个。
二阶线性数列递推,经典解法:
F
(
n
)
=
3
F
(
n
−
1
)
+
2
F
(
n
−
2
)
F(n)=3F(n-1)+2F(n-2)
F(n)=3F(n−1)+2F(n−2)
我们令 F ( n ) = r n F(n)=r^n F(n)=rn
所以特征多项式为:
r
2
−
3
r
−
2
=
0
r^2-3r-2=0
r2−3r−2=0
解得
r
1
=
3
+
17
2
,
r
2
=
3
−
17
2
r_1=\cfrac{3+\sqrt{17}}{2},r_2=\cfrac{3-\sqrt{17}}{2}
r1=23+17,r2=23−17
所以
F
(
n
)
=
c
1
r
1
n
+
c
2
r
2
n
F
(
n
)
=
c
1
(
3
+
17
2
)
n
+
c
2
(
3
−
17
2
)
n
\begin{aligned}F(n)&=c_1r_1^n+c_2r_2^n\\F(n)&=c_1(\cfrac{3+\sqrt{17}}{2})^n+c_2(\cfrac{3-\sqrt{17}}{2})^n\end{aligned}
F(n)F(n)=c1r1n+c2r2n=c1(23+17)n+c2(23−17)n
由题目中给出的
F
(
0
)
=
0
,
F
(
1
)
=
1
F(0)=0,F(1)=1
F(0)=0,F(1)=1
F
(
0
)
=
c
1
+
c
2
=
0
F
(
1
)
=
c
1
(
3
+
17
2
)
+
c
2
(
3
−
17
2
)
=
1
\begin{aligned}F(0)&=c_1+c_2=0\\F(1)&=c_1(\cfrac{3+\sqrt{17}}{2})+c_2(\cfrac{3-\sqrt{17}}{2})=1\end{aligned}
F(0)F(1)=c1+c2=0=c1(23+17)+c2(23−17)=1
解得
c
1
=
1
17
,
c
2
=
−
1
17
c_1=\cfrac{1}{\sqrt{17}},c_2=-\cfrac{1}{\sqrt{17}}
c1=171,c2=−171
故
F
(
n
)
=
1
17
(
(
3
+
17
2
)
n
−
(
3
−
17
2
)
n
)
F(n)=\cfrac{1}{\sqrt{17}}((\cfrac{3+\sqrt{17}}{2})^n-(\cfrac{3-\sqrt{17}}{2})^n)
F(n)=171((23+17)n−(23−17)n)
上面是推导过程,具体算法还涉及到q次询问,所以普通快速幂是不能实现的,时间复杂度过高,题解说的是预处理 r 0 , r 1 , ⋯   , r 1 e 9 r^0,r^1,\cdots,r^{\sqrt{1e9}} r0,r1,⋯,r1e9和 r 0 ⋅ 1 e 9 , r 1 ⋅ 1 e 9 , ⋯   , r 1 e 9 ⋅ 1 e 9 r^{0·\sqrt{1e9}},r^{1·\sqrt{1e9}},\cdots,r^{\sqrt{1e9}·\sqrt{1e9}} r0⋅1e9,r1⋅1e9,⋯,r1e9⋅1e9,做到了 O ( 1 ) O(1) O(1)的询问。
我是按照题解写的预处理,但是我觉得应该可以k进制快速幂, l o g 2 ( n ) log_2(n) log2(n)不够,就把2换成大一点的嘛,总归是可以的。
代码
// #include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <set>
#include <vector>
#include <assert.h>
#include <cmath>
#include <ctime>
using namespace std;
#define me(x,y) memset((x),(y),sizeof (x))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
// #define int __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int maxn = 1e6+10;
const int inf = __INT32_MAX__;
const ll INF = __LONG_LONG_MAX__;
const ll MOD = 998244353;
const double eps = 1e-10;
const double PI = std::acos(-1);
const ll ans17 = 524399943; //17的二次剩余
const int top = 1e9;
const int k = (int)sqrt(top);
ll qpow(ll a,ll b,ll p){
ll ans = 1;
while(b){ if(b&1) ans = ans*a%p; a=a*a%p;b >>= 1;}
return ans;
}
ll cnt1[maxn],cnt2[maxn],cnt11[maxn],cnt22[maxn];
const ll p2 = qpow(2,MOD-2,MOD); //2的逆元
const ll p17 = qpow(ans17,MOD-2,MOD); //sqrt(17)的逆元
const ll r1 = (3+ans17+MOD)*p2%MOD;//两个根
const ll r2 = (3-ans17+MOD)*p2%MOD;
void init(){
for(int i = 0; i*i <= top; ++i) cnt1[i] = qpow(r1,i,MOD),cnt2[i] = qpow(r2,i,MOD);
ll r11 = cnt1[k],r22 = cnt2[k];
for(int i = 0; i*i <= top; ++i) cnt11[i] = qpow(r11,i,MOD),cnt22[i] = qpow(r22,i,MOD);
}
map<ll,ll> mp;
ll f(ll n){
if(mp.count(n)) return mp[n]; //map记录
ll pre=0;
ll c = n/k,r = n%k;
pre = (cnt11[c]*cnt1[r]%MOD-cnt22[c]*cnt2[r]%MOD+MOD)%MOD;
pre = pre*p17%MOD;
mp[n] = pre;
return pre;
}
int main(){
ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("1in.in","r",stdin);
freopen("1out.out","w",stdout);
#endif
init();
ll n,q;
cin>>q>>n;
ll ans=0,fg=0;
while(q--){
ll pre = f(n%(MOD-1)); //n可能过大,欧拉降幂一下
n = n^(pre*pre);
ans = ans^pre;
// cout<<pre<<endl;
}
cout<<ans%MOD<<endl;
return 0;
}