BZOJ4002 [JLOI2015]有意義的字符串
阿新 • • 發佈:2019-02-23
reg std 乘法 bits zoj 一個數 pla template 推公式 ,並且 \(b \bmod 2=1,d \bmod 4=1\)
,所以\(\frac{b^2-d}{4}\)必然是整數。那麽\(a_n\)就可以用矩陣乘法解決了。那麽
\[ (\frac{b+\sqrt{d}}{2})^n = a_n - (\frac{b-\sqrt{d}}{2})^n \]
因為\(0<b^2 \le d<(b+1)^2\),所以\(\frac{b-\sqrt{d}}{2} \in (-1,0]\),題目要求的是下取整,所以當\(b^2<d,n \bmod 2 =0\)時,答案要減去1。
題意
Description
B 君有兩個好朋友,他們叫寧寧和冉冉。有一天,冉冉遇到了一個有趣的題目:輸入 b;d;n,求
\[
\lfloor \left ( \frac{b+\sqrt{d}}{2} \right ) ^n \rfloor \mathrm{mod} \ p
\]
其中\(p=7528443412579576937\)
Input
一行三個整數 b;d;n
Output
一行一個數表示模 7528443412579576937 之後的結果。
Sample Output
76
HINT
其中 \(0<b^2 \le d<(b+1)^2 \le 10^{18},n \le 10^{18}\)
分析
因為這個底數長得特別像特征方程的根,所以考慮構造數列,使得
\[
a_n = A*(\frac{b+\sqrt{d}}{2})^n + B*(\frac{b-\sqrt{d}}{2})^n
\]
假設特征方程是\(x^2 + bx +c=0\),則
\[
b = -b_0 \b^2 -4c = d_0
\]
所以得到數列的遞推公式:
\[
a_n = b a_{n-1} - \frac{b^2-d}{4} a_{n-2}
\]
由於我們想讓\(A=1,B=1\),所以\(a_0 = 2 ,a_1=b\)。
因為\(b \bmod 2=1,d \bmod 4=1\)
\[ (\frac{b+\sqrt{d}}{2})^n = a_n - (\frac{b-\sqrt{d}}{2})^n \]
因為\(0<b^2 \le d<(b+1)^2\),所以\(\frac{b-\sqrt{d}}{2} \in (-1,0]\),題目要求的是下取整,所以當\(b^2<d,n \bmod 2 =0\)時,答案要減去1。
時間復雜度\(O(2^3 \log n \log modulo)\)
代碼
#include<bits/stdc++.h> #define rg register #define il inline #define co const template<class T>il T read(){ rg T data=0,w=1; rg char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) data=data*10+ch-'0',ch=getchar(); return data*w; } template<class T>il T read(rg T&x){ return x=read<T>(); } typedef unsigned long long ULL; co ULL mod=7528443412579576937; ULL add(ULL x,ULL y){ return (x+=y)>=mod?x-mod:x; } ULL mul(ULL x,ULL y){ ULL re=0; for(;y;y>>=1,x=add(x,x)) if(y&1) re=add(re,x); return re; } ULL A[2][2],ANS[2][2],c[2][2]; void mul(ULL a[2][2],ULL b[2][2]){ for(int i=0;i<2;++i) for(int j=0;j<2;++j) for(int k=0;k<2;++k) c[i][j]=add(c[i][j],mul(a[i][k],b[k][j])); for(int i=0;i<2;++i) for(int j=0;j<2;++j) b[i][j]=c[i][j],c[i][j]=0; } ULL b,d,n; int main(){ // freopen(".in","r",stdin); // freopen(".out","w",stdout); read(b),read(d),read(n); A[0][0]=b,A[0][1]=(d-b*b)/4,A[1][0]=1; ANS[0][0]=b,ANS[1][0]=2; bool del=b*b<d&&n%2==0; for(;n;n>>=1,mul(A,A)) if(n&1) mul(A,ANS); printf("%llu\n",add(ANS[1][0],mod-del)); return 0; }
BZOJ4002 [JLOI2015]有意義的字符串