[BZOJ4002][JLOI2015]有意义的字符串-[快速乘法+矩阵乘法]
Description
Solution
由于这里带了小数,直接计算显然会爆掉,我们要想办法去掉小数。
而由于原题给了暗示:b2<=d<=(b+1)2,我们猜测可以利用$(\frac{b-\sqrt{d}}{2})^{n}$的范围为(-1,1)的性质。
则$ans=((\frac{b+\sqrt{d}}{2})^{n}+(\frac{b-\sqrt{d}}{2})^{n})-(\frac{b-\sqrt{d}}{2})^{n}$。
易得第一个括号里的式子不包含小数(强行组合数算一下就发现啦)
我们考虑特征方程,
现在定义$a_{n}=(\frac{b+\sqrt{d}}{2})^{n}+(\frac{b-\sqrt{d}}{2})^{n}$
解得$a_{n}=b*a_{n-1}+\frac{(d-b^{2})}{4}*a_{n-2}$
其中,边界a0=2,a1=b。
然后矩阵乘法就好啦。(备注:由于此处两个数相乘会过大,需要用到快速乘法,log(n)的那种)
最后,如果 $(\frac{b-\sqrt{d}}{2})^{n}\geqslant 0$,则由于题目向下取整,可以忽略;
故只有$b^{2}\neq d$且n为奇数才需要对答案减一。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; typedef unsigned long long ull; const ull mod=7528443412579576937ull; ull b,d,n; ull mul(ull a,ull b) { ull ans=0; while(b) { if(b&1) ans=(a+ans)%mod; b>>=1;a=(a+a)%mod; } return ans; } struct Matrix{ull x[3][3]; friend Matrix operator*(Matrix a,Matrix b) { Matrix c;memset(c.x,0,sizeof(c.x)); for (int i=1;i<=2;i++) for (int j=1;j<=2;j++) for (int k=1;k<=2;k++) c.x[i][j]=(c.x[i][j]+mul(a.x[i][k],b.x[k][j]))%mod; return c; } }a; Matrix ksm(Matrix a,ull t) { Matrix ans;memset(ans.x,0,sizeof(ans.x)); ans.x[1][1]=ans.x[2][2]=1; while (t) { if (t&1) ans=ans*a; t>>=1; a=a*a; } return ans; } ull ans; int main() { scanf("%llu%llu%llu",&b,&d,&n); if (!n) {printf("1");return 0;} a.x[1][1]=b; a.x[1][2]=(d-b*b)/4%mod; a.x[2][1]=1; a.x[2][2]=0; a=ksm(a,n-1); ans=(mul(b,a.x[1][1])+mul(2,a.x[1][2]))%mod; if (d!=b*b&&!(n&1)) ans--; if (ans<0) ans+=mod; cout<<ans; }