[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} eq 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;
} 
原文地址:https://www.cnblogs.com/coco-night/p/9545024.html