事先说一下:我是多校的时候ac的,比赛一停就当场换机子了,赛时是1800ms过的,赛后就TLE了,自己加速一下。
题目就是求斐波那契的:
这个题我和队友思索了很长时间,从各种性质到代换式子都不能解决。然后最后一点时间刚一下通项公式就做出来了。
通项公式:
F
n
=
(
5
)
5
∗
(
(
1
+
(
5
)
2
)
n
+
(
1
−
(
5
)
2
)
n
)
F_n=\frac {\sqrt(5)}{5}*((\frac{1+\sqrt(5)}{2})^n+(\frac{1-\sqrt(5)}{2})^n)
Fn=5(5)∗((21+(5))n+(21−(5))n)
为了方便计算和理解让
a=
1
+
(
5
)
2
\frac{1+\sqrt(5)}{2}
21+(5)
b=
1
−
(
5
)
2
\frac{1-\sqrt(5)}{2}
21−(5)
k次方对吧,我们可以说
(
(
5
)
F
c
)
k
(\sqrt(5)F_c)^k
((5)Fc)k的每一项是不是就是
C
k
i
∗
a
i
c
b
(
k
−
1
)
∗
c
C_k^i *a^{ic}b^{(k-1)*c}
Cki∗aicb(k−1)∗c
然后发现
(
(
5
)
F
2
c
)
k
(\sqrt(5)F_{2c})^k
((5)F2c)k的每一项竟然是
C
k
i
∗
a
i
∗
2
c
b
(
k
−
1
)
∗
2
c
C_k^i *a^{i*2c}b^{(k-1)*{2c}}
Cki∗ai∗2cb(k−1)∗2c
对应每一项是不是 F 2 c F_{2c} F2c都是 F c F_c Fc的平方,然后类推出来一个结论:
对第i项(
0
<
=
i
<
=
k
0<=i<=k
0<=i<=k):有一个等比数列,可以求前N项。
代码需要跑T*(K+1)次;
其实我是猜到要O(K)的。
为什么N、C都给了1e18范围,就K给了1e5?T是1e2,如果是O(T*K)时间就能过了,再加上20次常数,这不就是要求的2s吗?NC都不能直接一步一步算,所以一定会被压缩。我一开始想法是构造出来一个矩阵S。
S
k
S^k
Sk就是题目要求的结果。但是失败了。于是想一下到底NC是log级别的压缩还是O(1)的压缩。
最后推出答案。代码如下:(常数可能比较大,杭电换了比比赛时候更慢的机子,不能直接交,草了)
code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <iomanip>
//
using namespace std;
const int INF = 0x3f3f3f3f;//1.06e9大小
const int mod = 1e9 + 9;
const long long mod2 = 998244353;
const long long mod3 = 1e9;
const double PI = 3.14159265;
const double eps =1e-8;
typedef unsigned long long ULL;
typedef long long LL;
#define ms(x, n) memset(x,n,sizeof(x))
#define debug printf("***debug***\n")
#define pii pair<int ,int>
#define X first
#define Y second
#define pb push_back
//以下define不能在团队赛中使用
#define rep(i,from,to) for(int i=from;i<=to;++i)
#define per(i,from,to) for(int i=from:i>=to;--i)
/*
*/
const int MAXN=1e5+20;
const int sq5=616991993;
int t,k,jcn[MAXN],jc[MAXN],a[MAXN],b[MAXN];// a、b二项式两个单元
LL n,c;
//jcn 阶乘逆元,jc 阶乘;
inline LL ksm(LL x,LL n)
{
LL res=1;
LL base =x;
while(n)
{
if(n&1)res=res*base%mod;
base=base*base%mod;
n>>=1;
}
return res;
}
inline LL C(int n,int m)//组合
{
return 1LL*jcn[n]*jc[m]%mod*jc[n-m]%mod;
}
int main()
{
int t;
cin>>t;
jcn[0]=1;
for(int i=1;i<=100000;++i)
{
jcn[i]=1LL*jcn[i-1]*i%mod;
}
jc[100000]=ksm(jcn[100000],mod-2);
for(int i=100000;i;--i)
{
jc[i-1]=1LL*jc[i]*i%mod;
}
a[0]=b[0]=1;
for(int i=1;i<=100000;++i)
{
a[i]=1LL*a[i-1]*(1+sq5)%mod*jc[2]%mod,b[i]=1LL*b[i-1]*(1-sq5+mod)%mod*jc[2]%mod;
}
while(t--)
{
scanf("%lld %lld %d",&n,&c,&k);
LL ans=0;
for(int i=0;i<=k;++i)
{
LL tmp=1LL*a[i]*b[k-i]%mod,res=0;
tmp=ksm(tmp,c);
if(tmp==1)
{
res=C(k,i)*(n%mod)%mod;
}
else
{
res=C(k,i)*((ksm(tmp,(n+1)%(mod-1))-tmp+mod)%mod)%mod*ksm(tmp-1,mod-2)%mod;
}
if(!((k-i)&1))(ans+=res)%=mod;
else (ans+=mod-res)%=mod;
}
ans=ans*ksm(ksm(sq5,mod-2),k)%mod;
printf("%lld\n",ans);
}
return 0;
}