【BZOJ4002】[JLOI2015]有意义的字符串(数论,矩阵快速幂)

【BZOJ4002】[JLOI2015]有意义的字符串(数论,矩阵快速幂)

题面

BZOJ
洛谷

题解

发现我这种题总是做不动。。。
\(A=\frac{b+\sqrt d}{2},B=\frac{b-\sqrt d}{2}\)
发现\(A+B=b,AB=\frac{b^2-d}{4}\)
要求的东西是\(A^n\),我们变成\(A^n+B^n-B^n\)
分开考虑,发现\(A^n+B^n=(A^{n-1}+B^{n-1})(A+B)-(A^{n-2}+B^{n-2})AB\),这样子前面一半可以矩乘直接求。
后面一般根据数据范围,发现要么是\(0\),要么是\(-1\)
那么直接特判一下就可以求了。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
const ll MOD=7528443412579576937ll;
ll Multi(ll a,ll b){ll s=a*b-(ll)((long double)a/MOD*b+0.5)*MOD;return s<0?s+MOD:s;}
ll Plus(ll a,ll b){unsigned ll c=(0ull+a+b)%MOD;return c;}
ll b,d,n,ans;
struct Matrix
{
    ll s[2][2];
    void clear(){s[0][0]=s[0][1]=s[1][0]=s[1][1]=0;}
    void init(){s[0][0]=s[1][1]=1;s[1][0]=s[0][1]=0;}
    ll*operator[](int x){return s[x];}
}T;
Matrix operator*(Matrix a,Matrix b)
{
    Matrix c;c.clear();
    for(int i=0;i<2;++i)
        for(int j=0;j<2;++j)
            for(int k=0;k<2;++k)
                c[i][j]=Plus(c[i][j],Multi(a[i][k],b[k][j]));
    return c;
}
int main()
{
    scanf("%lld%lld%lld",&b,&d,&n);
    if(!n){puts("1");return 0;}
    T[0][0]=0;T[0][1]=(d-b*b)/4;
    T[1][0]=1;T[1][1]=b;
    if(!(n&1)&&b*b<d)ans=MOD-1;
    Matrix s;s.init();n-=1;
    while(n){if(n&1)s=s*T;T=T*T;n>>=1;}
    ans=Plus(ans,Plus(Multi(2,s[0][1]),Multi(b,s[1][1])));
    printf("%lld\n",ans);
    return 0;
}
        
posted @ 2019-04-24 22:30 小蒟蒻yyb 阅读(...) 评论(...) 编辑 收藏