解析
去你的搬砖生成函数,特征根太香了。
一开始我是用生成函数解的,和特征根相比有亿点点搬砖…
但是这个东西原理似乎使用一些神奇的等比差分,有些玄学,生成函数较易理解。
背下来背下来!
就以本题为情境讲一下特征根方程的解题流程吧。
对于递推式:
a
n
=
233
a
n
−
1
+
666
a
n
−
2
a_n=233a_{n-1}+666a_{n-2}
an=233an−1+666an−2
其特征方程就是:
x
2
=
233
x
+
666
x^2=233x+666
x2=233x+666
解得两个根:
p
1
=
233
+
56953
2
p_1=\frac{233+\sqrt{56953}}{2}
p1=2233+56953
p
2
=
233
−
56953
2
p_2=\frac{233-\sqrt{56953}}{2}
p2=2233−56953
那么通项公式就可以写成
a
n
=
c
1
p
1
n
+
c
2
p
2
n
a_n=c_1p_1^n+c2p_2^n
an=c1p1n+c2p2n
当解得的 p 1 = p 2 = p p_1=p_2=p p1=p2=p 时,通项会变成: a n = ( c 1 + c 2 n ) p n a_n=(c_1+c_2n)p^n an=(c1+c2n)pn
然后带入
a
0
,
a
1
a_0,a_1
a0,a1 解出
c
0
,
c
1
c_0,c_1
c0,c1:
0
=
c
1
+
c
2
0=c_1+c_2
0=c1+c2
1
=
c
1
p
1
+
c
2
p
2
1=c_1p_1+c_2p_2
1=c1p1+c2p2
解得
c
1
=
1
56953
c_1=\frac{1}{\sqrt{56953}}
c1=569531
c
2
=
−
1
56953
c_2=-\frac{1}{\sqrt{56953}}
c2=−569531
带回原式:
a
n
=
(
233
+
56953
2
)
n
−
(
233
−
56953
2
)
n
56953
a_n=\frac{(\dfrac{233+\sqrt{56953}}{2})^n-(\dfrac{233-\sqrt{56953}}{2})^n}{\sqrt{56953}}
an=56953(2233+56953)n−(2233−56953)n
然后有一个很重要的技巧:寻找
56953
56953
56953 在对
1
e
9
+
7
1e9+7
1e9+7 的模意义下是否是二次剩余。
出题人总会给人一条活路,写个暴力跑一会就能找到:
18830583
7
2
≡
56953
(
m
o
d
1
0
9
+
7
)
188305837^2\equiv 56953\pmod{10^9+7}
1883058372≡56953(mod109+7)
所以式子就变成了:
a
n
=
(
233
+
188305837
2
)
n
−
(
233
−
188305837
2
)
n
188305837
a_n=\frac{(\dfrac{233+188305837}{2})^n-(\dfrac{233-188305837}{2})^n}{188305837}
an=188305837(2233+188305837)n−(2233−188305837)n
化简得:
a
n
=
9415303
5
n
−
90584720
5
n
188305837
a_n=\frac{94153035^n-905847205^n}{188305837}
an=18830583794153035n−905847205n
再把逆元提前算出来:
a
n
=
233230706
(
9415303
5
n
−
90584720
5
n
)
a_n=233230706(94153035^n-905847205^n)
an=233230706(94153035n−905847205n)
其中的指数
n
n
n 可以用欧拉定理缩小到
O
(
m
o
d
)
O(mod)
O(mod) 范围。
然后问题就变成了如何快速求这个东西。
可以使用光速幂
原理很好理解,使用类似分块的思路,设
p
=
m
o
d
p=\sqrt{mod}
p=mod,
O
(
(
m
o
d
)
)
O(\sqrt(mod))
O((mod)) 预处理所有
x
k
p
(
k
≤
⌊
m
o
d
p
⌋
)
x^{kp}(k\le\lfloor \frac{mod}{p}\rfloor)
xkp(k≤⌊pmod⌋) 和
x
k
(
k
<
p
)
x^k(k<p)
xk(k<p),然后任意幂次都可以转化成
x
⌊
k
p
⌋
∗
p
×
x
k
%
p
x^{\lfloor\frac{k}{p}\rfloor*p}\times x^{k\%p}
x⌊pk⌋∗p×xk%p,然后实现
O
(
1
)
O(1)
O(1) 计算。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=4e5+100;
const int mod=1e9+7;
int n,m,k;
inline ll ksm(ll x,ll k){
ll res=1;
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;k>>=1;
}
return res;
}
int niv2=ksm(2,mod-2);
int r[N];
void init(int n,int &lim){
lim=1;int L=0;
while(lim<n) lim<<=1,L++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
}
void NTT(ll *x,int lim,int op){
for(int i=0;i<lim;i++) if(i<r[i]) swap(x[i],x[r[i]]);
for(int l=1;l<lim;l<<=1){
ll w=ksm(3,(mod-1)/(l<<1));if(op==-1) w=ksm(w,mod-2);
for(int st=0;st<lim;st+=(l<<1)){
for(ll i=0,now=1;i<l;i++,now=now*w%mod){
ll u=x[st+i],v=now*x[st+i+l]%mod;
x[st+i]=u+v>=mod?u+v-mod:u+v;
x[st+i+l]=u-v<0?u-v+mod:u-v;
}
}
}
if(op==-1){
ll ni=ksm(lim,mod-2);
for(int i=0;i<lim;i++) x[i]=x[i]*ni%mod;
}
return;
}
void copy(ll *a,ll *b,int n,int lim){
assert(n<=lim);
memcpy(a,b,sizeof(ll)*n);
fill(a+n,a+lim,0);return;
}
void mul(ll *a,ll *b,ll *c,int n,int m){
static ll u[N],v[N];
static int lim;
//for(int i=0;i<n;i++) printf("%lld ",a[i]);putchar('\n');
//for(int i=0;i<m;i++) printf("%lld ",b[i]);putchar('\n');
init(n+m-1,lim);
copy(u,a,n,lim);
copy(v,b,m,lim);
NTT(u,lim,1);NTT(v,lim,1);
for(int i=0;i<lim;i++) c[i]=u[i]*v[i]%mod;
NTT(c,lim,-1);
//for(int i=0;i<n+m-1;i++) printf("%lld ",c[i]);putchar('\n');
//putchar('\n');
return;
}
void inv(ll *h,ll *f,int n){
static ll t1[N],t2[N];
static int lim;
if(n==1){
f[0]=ksm(h[0],mod-2);return;
}
inv(h,f,(n+1)>>1);
init(n<<1,lim);
fill(f+((n+1)>>1),f+lim,0);
copy(t1,f,n,lim);copy(t2,h,n,lim);
NTT(t1,lim,1);NTT(t2,lim,1);
for(int i=0;i<lim;i++) t1[i]=(2*t1[i]-t1[i]*t1[i]%mod*t2[i]%mod+mod)%mod;
NTT(t1,lim,-1);
memcpy(f,t1,sizeof(ll)*n);
return;
}
//499122177
void Sqrt(ll *h,ll *f,int n){
static ll t1[N],t2[N];
static int lim;
if(n==1){
f[0]=1;return;
}
Sqrt(h,f,(n+1)>>1);
init(n<<1,lim);
fill(f+((n+1)>>1),f+lim,0);
inv(f,t1,n);
fill(t1+n,t1+lim,0);
mul(h,t1,t1,n,n);
copy(t2,f,n,lim);
NTT(t1,lim,1);NTT(t2,lim,1);
for(int i=0;i<lim;i++) t1[i]=(t1[i]+t2[i])*niv2%mod;
NTT(t1,lim,-1);
memcpy(f,t1,sizeof(ll)*n);
return;
}
void dao(ll *h,ll *f,int n){
static ll t[N];
static int lim;
init(n<<1,lim);
copy(t,h,n,lim);
f[n-1]=0;
for(int i=0;i<n-1;i++) f[i]=t[i+1]*(i+1)%mod;
fill(f+n,f+lim,0);
return;
}
void jifen(ll *h,ll *f,int n){
static ll t[N];
static int lim;
init(n<<1,lim);
copy(t,h,n,lim);
f[0]=0;
for(int i=1;i<n;i++) f[i]=h[i-1]*ksm(i,mod-2)%mod;
fill(f+n,f+lim,0);
}
void Ln(ll *h,ll *f,int n){
static ll t1[N],t2[N];
static int lim;
init(n<<1,lim);
inv(h,t1,n);
fill(t1+n,t1+lim,0);
dao(h,t2,n);
mul(t1,t2,t1,n,n);
jifen(t1,f,n);
return;
}
void Exp(ll *h,ll *f,int n){
static ll t1[N],t2[N],t3[N];
static int lim;
if(n==1){
f[0]=1;return;
}
Exp(h,f,(n+1)>>1);
init(n<<1,lim);
fill(f+((n+1)>>1),f+lim,0);
copy(t1,f,n,lim);
copy(t2,h,n,lim);
Ln(f,t3,n);fill(t3+n,t3+lim,0);
NTT(t1,lim,1);NTT(t2,lim,1);NTT(t3,lim,1);
for(int i=0;i<lim;i++) t1[i]=t1[i]*(1+t2[i]-t3[i]+mod)%mod;
NTT(t1,lim,-1);
memcpy(f,t1,sizeof(ll)*n);
return;
}
struct KSM{
int w,x;
ll u[N],v[N];
void init(int base){
x=base;
w=sqrt(mod);
v[0]=1;
for(int i=1;i<w;i++) v[i]=v[i-1]*x%mod;
ll o=v[w-1]*x%mod;
u[0]=1;
for(int i=1;i<=mod/w;i++) u[i]=u[i-1]*o%mod;
return;
}
inline ll calc(int k){
int a=k/w,b=k%w;
return u[a]*v[b]%mod;
}
}a,b;
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;
}
signed main() {
#ifndef ONLINE_JUDGE
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#endif
int T=read();
init();
a.init(94153035);b.init(905847205);
ll ans(0);
while(T--){
ll o=Rand()%(mod-1);
ans^=(233230706ll*(a.calc(o)+mod-b.calc(o))%mod);
}
printf("%lld\n",ans);
return 0;
}
/*
*/