正题
题目链接:https://www.luogu.com.cn/problem/P5110
题目大意
数列aaa满足
an=233an−1+666an−2,a0=0,a1=1a_n=233a_{n-1}+666a_{n-2},a_0=0,a_1=1an=233an−1+666an−2,a0=0,a1=1
TTT组询问给出nnn求ana_nan
1≤T≤5×1071\leq T\leq 5\times 10^71≤T≤5×107,nnn在unsigned long long\text{unsigned long long}unsigned long long范围内
解题思路
上面那个递推式的特征方程就是x2−233x−666x^2-233x-666x2−233x−666,直接带式子解出来x0=233+569532,x1=233−569532x_0=\frac{233+\sqrt{56953}}{2},x_1=\frac{233-\sqrt{56953}}{2}x0=2233+56953,x1=2233−56953。
然后设an=c0x0n+c1x1na_n=c_0x_0^n+c_1x_1^nan=c0x0n+c1x1n,那么带入a0a_0a0和a1a_1a1就有
{c0+c1=0c0233+569532+c1233−569532=1\left\{\begin{matrix}c_0+c_1=0\\c_0\frac{233+\sqrt{56953}}{2}+c_1\frac{233-\sqrt{56953}}{2}=1\end{matrix}\right.{c0+c1=0c02233+56953+c12233−56953=1
解出来有c0=156953,c1=−156953c_0=\frac{1}{\sqrt{56953}},c_1=-\frac{1}{\sqrt{56953}}c0=569531,c1=−569531。
这样我们就可以O(Tlogn)O(T\log n)O(Tlogn)求答案了,但是还是不够。
先根据欧拉定理让nnn模上φ(P)\varphi(P)φ(P)缩小范围
然后分块处理快速幂,处理出xix^ixi和xiP(i∈[0,P])x^{i\sqrt P}(i\in[0,\sqrt P])xiP(i∈[0,P]),这个是O(P)O(\sqrt P)O(P)的,然后每次把nnn分为整块的成上末尾的就好了。
时间复杂度O(P+T)O(\sqrt P+T)O(P+T)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const ll P=1e9+7,Phi=P-1;
const ll sq=188305837,T=32000;
ll Q,n,p0[T+1],p1[T+1],P0[T+1],P1[T+1],ans;
ll pw0(ll x){return P0[x/T]*p0[x%T]%P;}
ll pw1(ll x){return P1[x/T]*p1[x%T]%P;}
namespace Mker
{unsigned long long SA,SB,SC;void init(){scanf("%llu%llu%llu",&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%Phi;}
}
signed main()
{ll inv2=(P+1)/2;ll x0=(233+sq)*inv2%P,x1=(P+233-sq)*inv2%P;p0[0]=p1[0]=P0[0]=P1[0]=1;for(ll i=1;i<=T;i++)p0[i]=p0[i-1]*x0%P,p1[i]=p1[i-1]*x1%P;for(ll i=1;i<=T;i++)P0[i]=P0[i-1]*p0[T]%P,P1[i]=P1[i-1]*p1[T]%P;ll inv=233230706,c0=inv,c1=P-inv;scanf("%lld",&Q);Mker::init();while(Q--){n=Mker::rand();
// scanf("%lld",&n);ans=0;ans^=(c0*pw0(n)+c1*pw1(n))%P;
// printf("%lld\n",ans);}printf("%lld\n",ans);
}