[JLOI2015] bzoj 4002 有意义的字符串 - 常系数线性递推

博客介绍根据数学知识,对于形如fn=pfn−1+qfn−2的数列,利用方程x2−px−q=0的根将fn表示为fn=Axn1+Bxn2形式,结合题目条件求出p、q、f0、f1,可知fn为整数,再用矩阵乘法递推,最后得出答案并处理误差。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据一些数学知识可以知道形如fn=pfn1+qfn2fn=pfn−1+qfn−2的数列,设方程x2pxq=0x2−px−q=0存在两实数根为x1,x2x1,x2,则fnfn可以被表示为fn=Axn1+Bxn2fn=Ax1n+Bx2n的形式,且通过f0,f1f0,f1可以求出AAB。在本题中取x1=b+d2,x2=bd2,A=B=1x1=b+d2,x2=b−d2,A=B=1,可以求出上文中的p,q,f0,f1p,q,f0,f1。通过题目限制可以发现四者都是整数,因此fnfn也是整数。
然后用矩阵乘法做递推即可。最后答案等于fnxn2fn−x2n,注意到|x2|<1|x2|<1,所以最多只有1的误差,特判即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define mod 7528443412579576937ll
#define lint long long
#define ull unsigned long long
using namespace std;
inline lint pls(lint a,lint b) { return (lint)(((ull)a+b)%mod); }
inline lint tms(lint a,lint b,lint ans=0)
{   for(;b;b>>=1,a=pls(a,a)) (b&1ll)?ans=pls(ans,a):0;return ans;   }
struct node{
    lint a,b,c,d;
    node(lint _a=1,lint _b=0,lint _c=0,lint _d=1)
    {   a=_a,b=_b,c=_c,d=_d;    }
    inline node operator=(const node &n)
    {   return a=n.a,b=n.b,c=n.c,d=n.d,*this;   }
    inline node operator*(const node &n)const
    {
        node r;
        r.a=pls(tms(a,n.a),tms(b,n.c)),
        r.b=pls(tms(a,n.b),tms(b,n.d)),
        r.c=pls(tms(c,n.a),tms(d,n.c)),
        r.d=pls(tms(c,n.b),tms(d,n.d));
        return r;
    }
    inline node operator*=(const node &n)
    {   return (*this)=(*this)*n;   }
};
inline node fast_pow(node x,lint k,node ans=node())
{   for(;k;k>>=1,x*=x) (k&1ll)?ans*=x,0:0;return ans;   }
int main()
{
    lint b,d,n;scanf("%lld%lld%lld",&b,&d,&n);
    node t=fast_pow(node(b,(d-b*b)/4%mod,1,0),n);
    lint ans=pls(tms(t.c,b),tms(t.d,2));
    if(n%2==0&&d!=b*b) ans=(lint)((ans-1ull+mod)%mod);
    return !printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值