题目大意:
求斐波那契数列前n项的k次幂和 Mod 1000000009。 n<=1e18, k<=1e5
这题的k比较大,所以不能用矩阵乘法来递推。学到了新姿势... http://blog.csdn.net/acdreamers/article/details/23039571
基本思想就是求出通项公式,把里面的$\sqrt{5}$ 用 $x$ 代替, 其中 $x^2\equiv 5\pmod{1000000009}$
然后二项式展开求和就好了。
一个合法的$x$是383008016。 正好前几天做了个高次剩余方程的题,直接拉过去跑出来。。
为什么这样替代是合法的呢? 网络上好像没找到严谨的证明。
下面给出我个人的不严谨证明:
将原式子合并之后最终会得到$\frac{P(t)}{Q(t)}$ 这样的形式。 其中$t=\sqrt{5}$ $P(t)$和$Q(t)$是关于$t$的多项式.
把$P(t)$ $Q(t)$中次数>=2的可以利用$t^2=5$降幂成次数不超过1的, 最后变成$\frac{P'(t)}{Q'(t)}$ 这样的形式.
由于最终答案一定是整数,所以 $Q'(t)$ 能整除 $P'(t)$ 。 设 $\frac{P'(t)}{Q'(t)}=K$
那么把$t$ 换成 上面求出的 $x$ 得到的 $\frac{P'(x)}{Q'(x)}$ 也是 $K$. 不影响答案。
AC代码:


1 #include2 #include ]*i%Mod,fac_inv[i]=Power(fac[i],Mod-2); 54 int T,K,ans; ll n; 55 scanf("%d",&T); 56 while (T--) 57 { 58 scanf("%lld%d",&n,&K); 59 ans=0; 60 for (int i=K,op=1;i>=0;i--,op=-op) 61 { 62 int tmp1=op*C(K,i),tmp2,x=1ll*Power(P,i)*Power(Q,K-i)%Mod; 63 if (x==1) tmp2=n%Mod; 64 else tmp2=1ll*x*(Power(x,n)-1)%Mod,tmp2=1ll*tmp2*Power(x-1,Mod-2)%Mod; 65 ans+=1ll*tmp1*tmp2%Mod; 66 ans%=Mod; 67 } 68 if (ans<0) ans+=Mod; 69 ans=1ll*ans*Power(Power(sqrt5,Mod-2),K)%Mod; 70 printf("%d\n",ans); 71 } 72 return 0; 73 }3 #include 4 #include 5 #include 6 #include 7 #include
我的求高次剩余方程的代码(目前只会做模数是质数的情况...):
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1038


1 #include2 #include ,int> > hash[M]; 58 59 int Calc_Exp(int a,int b,int P) // 求解a^x=b (mod P) 60 { 61 int m=ceil(sqrt(P+0.5)); 62 for (int i=0;i3 #include 4 #include 5 #include ) hash[i].clear(); 63 64 int v=Power(a,m,P),tmp=1; v=Power(v,P-2,P); 65 hash[1].push_back(make_pair(1,0)); 66 for (int i=1;i ) 67 { 68 tmp=1ll*tmp*a%P; 69 hash[tmp%M].push_back(make_pair(tmp,i)); 70 } 71 72 for (int i=0;i ) 73 { 74 int t=b%M; 75 for (int j=0;j ) 76 { 77 if (hash[t][j].X==b) return i*m+hash[t][j].Y; 78 } 79 b=1ll*b*v%P; 80 } 81 } 82 83 void ex_gcd(ll a,ll b,ll &x,ll &y,ll &d) 84 { 85 if (!b) 86 { 87 d=a; 88 x=1; 89 y=0; 90 } 91 else 92 { 93 ex_gcd(b,a%b,y,x,d); 94 y-=a/b*x; 95 } 96 } 97 98 //X^A = B (mod P) 99 void Solve_Equation(int A,int B,int P) 100 { 101 ans.clear(); 102 int g=Find_Root(P); //求出P的原根 103 int b=Calc_Exp(g,B,P); // B=g^b 104 ll x,y,d; 105 ex_gcd(A,P-1,x,y,d); 106 if (b%d==0) 107 { 108 int del=(P-1)/d,tmp,t; 109 x*=b/d; 110 x%=del; 111 if (x<0) x+=del; 112 tmp=Power(g,(int)x,P); 113 t=Power(g,del,P); 114 while (x<=P-2) ans.push_back(tmp),x+=del,tmp=1ll*tmp*t%P; 115 sort(ans.begin(),ans.end()); 116 for (int i=0;i "%d%c",ans[i],i==ans.size()-1? '\n':' '); 117 } 118 if (ans.size()==0) printf("No Solution\n"); 119 } 120 121 int main() 122 { 123 //freopen("in.in","r",stdin); 124 //freopen("out.out","w",stdout); 125 126 for (int i=2;i ) 127 { 128 if (!flag[i]) prime[++prime[0]]=i; 129 for (int j=1;j<=prime[0] && i*prime[j] ) 130 { 131 flag[i*prime[j]]=true; 132 if (i%prime[j]==0) break; 133 } 134 } 135 136 int T,A,B,P; scanf("%d",&T); 137 while (T--) 138 { 139 scanf("%d%d%d",&P,&A,&B); 140 Solve_Equation(A,B,P); 141 } 142 143 return 0; 144 }
可以扩展到模数不是质数的情况,等我学会了在写篇文章 记录具体做法吧。