背景:
偶然发现
luogu rank1
\text{luogu rank1}
luogu rank1巨佬推荐这道题,就进来做做。
大水题。
题目传送门:
https://www.luogu.org/problemnew/show/SP31428
题意:
给定
n
,
x
n,x
n,x,求
D
(
n
,
x
)
=
∑
i
=
1
n
f
i
x
i
D(n,x)=\sum_{i=1}^{n}f_ix^i
D(n,x)=∑i=1nfixi。其中
f
f
f为
Fibonacci
\text{Fibonacci}
Fibonacci序列,
f
1
=
1
,
f
2
=
1
,
f
n
=
f
n
−
1
+
f
n
−
2
f_1=1,f_2=1,f_n=f_{n-1}+f_{n-2}
f1=1,f2=1,fn=fn−1+fn−2。
思路:
这种数据范围显然要用矩阵乘法优化或考虑通项式。
我们在生成函数——OGF证明了
Fibonacci
\text{Fibonacci}
Fibonacci序列的通项式为:
1
5
(
(
1
+
5
2
)
n
−
(
1
−
5
2
)
n
)
\frac{1}{\sqrt{5}}\left((\frac{1+\sqrt{5}}{2})^{n}-(\frac{1-\sqrt{5}}{2})^{n}\right)
51((21+5)n−(21−5)n),也就是说:
D
(
n
,
x
)
=
∑
i
=
1
n
1
5
(
(
1
+
5
2
)
i
−
(
1
−
5
2
)
i
)
x
i
D(n,x)=\sum_{i=1}^{n}\frac{1}{\sqrt{5}}\left((\frac{1+\sqrt{5}}{2})^{i}-(\frac{1-\sqrt{5}}{2})^{i}\right)x^i
D(n,x)=i=1∑n51((21+5)i−(21−5)i)xi
D ( n , x ) = 1 5 ∑ i = 1 n ( ( 1 + 5 2 x ) i − ( 1 − 5 2 x ) i ) D(n,x)=\frac{1}{\sqrt{5}}\sum_{i=1}^{n}\left((\frac{1+\sqrt{5}}{2}x)^{i}-(\frac{1-\sqrt{5}}{2}x)^{i}\right) D(n,x)=51i=1∑n((21+5x)i−(21−5x)i)
D ( n , x ) = 5 5 ( ∑ i = 1 n ( x + 5 x 2 ) i − ∑ i = 1 n ( x − 5 x 2 ) i ) D(n,x)=\frac{\sqrt{5}}{5}\left(\sum_{i=1}^{n}(\frac{x+\sqrt{5}x}{2})^{i}-\sum_{i=1}^{n}(\frac{x-\sqrt{5}x}{2})^{i}\right) D(n,x)=55(i=1∑n(2x+5x)i−i=1∑n(2x−5x)i)
注意到两个 ∑ \sum ∑其实就是等比数列求和,剩下的等比数列求和即可。
如何解决
5
\sqrt{5}
5呢?
考虑到
5
\sqrt{5}
5在
m
o
d
  
(
1
0
9
+
7
)
\mod (10^9+7)
mod(109+7)下没有二次剩余,因此我们可以扩域。
简单来说就是令
z
=
x
+
y
i
z=x+yi
z=x+yi,其中
i
=
5
i=\sqrt{5}
i=5的形式。
然后类似复数的计算,有:
z
1
±
z
2
=
(
x
1
+
y
1
i
)
±
(
x
2
+
y
2
i
)
=
(
x
1
±
x
2
)
+
(
y
1
±
y
2
)
i
z1±z2=(x1+y1i)±(x2+y2i)=(x1±x2)+(y1±y2)i
z1±z2=(x1+y1i)±(x2+y2i)=(x1±x2)+(y1±y2)i;
z
1
⋅
z
2
=
(
x
1
+
y
1
i
)
(
x
2
+
y
2
i
)
=
(
x
1
x
2
)
+
(
x
1
y
2
+
x
2
y
1
)
i
+
y
1
y
2
i
2
=
(
x
1
x
2
+
5
y
1
y
2
)
+
(
x
1
y
2
+
x
2
y
1
)
i
z1\cdot z2=(x1+y1i)(x2+y2i)=(x1x2)+(x1y2+x2y1)i+y1y2i^2=(x1x2+5y1y2)+(x1y2+x2y1)i
z1⋅z2=(x1+y1i)(x2+y2i)=(x1x2)+(x1y2+x2y1)i+y1y2i2=(x1x2+5y1y2)+(x1y2+x2y1)i;
1
z
=
1
x
+
y
i
=
x
−
y
i
(
x
+
y
i
)
(
x
−
y
i
)
=
x
x
2
−
5
y
2
−
y
x
2
−
5
y
2
i
\frac{1}{z}=\frac{1}{x+yi}=\frac{x-yi}{(x+yi)(x-yi)}=\frac{x}{x^2-5y^2}-\frac{y}{x^2-5y^2}i
z1=x+yi1=(x+yi)(x−yi)x−yi=x2−5y2x−x2−5y2yi
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define mod 1000000007
using namespace std;
struct comp
{
LL x,y;
comp(LL xx=0,LL yy=0):x(xx),y(yy) {}
friend comp operator+(const comp &a,const comp &b) {return comp((a.x+b.x)%mod,(a.y+b.y)%mod);}
friend comp operator-(const comp &a,const comp &b) {return comp((a.x-b.x+mod)%mod,(a.y-b.y+mod)%mod);}
friend comp operator*(const comp &a,const comp &b) {return comp((a.x*b.x%mod+5ll*a.y*b.y%mod)%mod,(a.x*b.y%mod+b.x*a.y%mod)%mod);}
};
LL dg1(LL x,LL k)
{
if(!k) return 1;
LL op=dg1(x,k>>1);
return (k&1)?op*op%mod*x%mod:op*op%mod;
}
LL inv1(LL x)
{
return dg1(x,mod-2);
}
comp dg2(comp x,LL k)
{
if(!k) return comp(1,0);
comp op=dg2(x,k>>1);
return (k&1)?op*op*x:op*op;
}
comp inv2(comp now)
{
LL x=now.x,y=now.y;
LL t=dg1((x*x%mod-5ll*y*y%mod+mod)%mod,mod-2);
return comp(x*t%mod,(-y*t%mod+mod)%mod);
}
comp work(LL n,comp now)
{
return (dg2(now,n+1)-now)*inv2(now-comp(1,0));
}
int main()
{
int T;
LL n,x;
LL inv2=inv1(2),inv5=inv1(5);
scanf("%d",&T);
while(T--)
{
scanf("%lld %lld",&n,&x);
comp a=comp(inv2*x%mod,inv2*x%mod),b=comp(inv2*x%mod,(-inv2+mod)%mod*x%mod);
printf("%lld\n",(comp(0,inv5)*(work(n,a)-work(n,b))).x);
}
}