luogu3263/bzoj4002 有意义的字符串 (数学+矩阵快速幂)

首先我们发现$\frac{b+\sqrt{d}}{2}$这个形式好像一元二次方程的求根公式啊(???反正我发现不了)

然后我们又想到虽然这个东西不好求但是$(\frac{b-\sqrt{d}}{2})^n$好像挺好求的啊(???反正我想不到)(由题目给的范围,这玩意在(-1,1))

于是把这个方程写出来:$x^2-b+\frac{b^2-d}{4}=0$,设它的两根是$x_1=\frac{b+\sqrt{d}}{2} , x_2=\frac{b-\sqrt{d}}{2}$

于是就是要求$\lfloor x_1^n+x_2^n-x_2^n \rfloor$

我们把$x_1^n+x_2^n$单拎出来,分解一下,得到$x_1^n+x_2^n = (x_1+x_2)(x_1^{n-1}+x_2^{n-1}) - x_1x_2(x_1^{n-2}+x_2^{n-2}) $

然后$x_1+x_2$和$x_1x_2$可以用韦达定理算,再把$x_1^i+x_2^i$设成f[i],就可以用矩阵快速幂优化了

可以发现它是个整数,最后讨论一下$x_2^n$就行了

(模数巨大,不光要用龟速乘,还要用unsigned long long)

 1 #include<bits/stdc++.h>
 2 #define CLR(a,x) memset(a,x,sizeof(a))
 3 using namespace std;
 4 typedef long long ll;
 5 typedef unsigned long long ull;
 6 typedef pair<int,int> pa;
 7 const ull P=7528443412579576937;
 8 
 9 inline ll rd(){
10     ll x=0;char c=getchar();int neg=1;
11     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
13     return x*neg;
14 }
15 
16 ull fmul(ull a,ull b){
17     ull re=0;
18     while(b){
19         if(b&1) re=(re+a)%P;
20         a=(a+a)%P,b>>=1;
21     }return re;
22 }
23 
24 ull b,d,n;
25 
26 ull fpow(ull x){
27     ull f[2];f[0]=b,f[1]=2;
28     ull m[2][2],tmp[2][2];
29     m[0][0]=b,m[0][1]=1,m[1][0]=(d-b*b)/4,m[1][1]=0;
30     while(x){
31         if(x&1){
32             CLR(tmp,0);
33             for(int i=0;i<=1;i++){
34                 for(int j=0;j<=1;j++){
35                     tmp[0][i]=(tmp[0][i]+fmul(f[j],m[j][i]))%P;
36                 }
37             }
38             f[0]=tmp[0][0],f[1]=tmp[0][1];
39         }
40         CLR(tmp,0);
41         for(int i=0;i<=1;i++){
42             for(int j=0;j<=1;j++){
43                 for(int k=0;k<=1;k++){
44                     tmp[i][j]=(tmp[i][j]+fmul(m[i][k],m[k][j]))%P;
45                 }
46             }
47         }
48         memcpy(m,tmp,sizeof(m));
49         x>>=1;
50     }return f[0];
51 }
52 
53 int main(){
54     //freopen("","r",stdin);
55     int i,j,k;
56     b=rd(),d=rd(),n=rd();
57     if(n==0) printf("1\n");
58     else{
59         ull ans=fpow(n-1);
60         if(!(n&1)&&d!=b*b) ans=(P+ans-1)%P;
61         printf("%lld\n",ans);
62     }
63 
64     return 0;
65 }

 

posted @ 2018-11-15 18:46  Ressed  阅读(142)  评论(0编辑  收藏  举报