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

博客围绕求解 (b + d√2)^n 展开,因该数为无理数且值大无法直接计算,通过分析将问题转化为求 ⌊[(b + d√2)^n + (b - d√2)^n] - (b - d√2)^n⌋,拆分为两部分求解,第一部分用韦达定理推出递推式,用矩阵快速递推;第二部分判断对答案的贡献,还提及避免爆 long long 的处理方法。

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

看来我数学还是太弱了,这道题也没有想到。
我们发现 (b+d2)n ( b + d 2 ) n 是个无理数,而且这个数非常大,所以无法直接计算。我们又发现 (bd2)n ( b − d 2 ) n 的值虽然是个无理数,但是他的值向下取整之后非常好计算。然后我们又发现, (b+d2)n+(bd2)n ( b + d 2 ) n + ( b − d 2 ) n 是个有理数,又因为 b mod 2=1,d mod 4=1 b   m o d   2 = 1 , d   m o d   4 = 1 ,所以不难证明这个数是一个整数。
所以,我们可以将问题转变为求 [(b+d2)n+(bd2)n](bd2)n ⌊ [ ( b + d 2 ) n + ( b − d 2 ) n ] − ( b − d 2 ) n ⌋
然后我们就可以把问题拆成两部分。
首先我们考虑第一部分。我们可以构造一个一元二次方程: x2b+b2d4=0 x 2 − b + b 2 − d 4 = 0 ,那么它的解 x1=b+d2,x2=bd2 x 1 = b + d 2 , x 2 = b − d 2
那么第一部分就等于 xn1+xn2 x 1 n + x 2 n
然后我们把这个式子变形一下就可以得到: xn1+xn2=(x1+x2)(xn11+xn12)x1x2(xn21+xn22) x 1 n + x 2 n = ( x 1 + x 2 ) ( x 1 n − 1 + x 2 n − 1 ) − x 1 x 2 ( x 1 n − 2 + x 2 n − 2 )
然后令 F(n)=xn1+xn2 F ( n ) = x 1 n + x 2 n
可以得到 F(n)=(x1+x2)F(n1)x1x2F(n2) F ( n ) = ( x 1 + x 2 ) F ( n − 1 ) − x 1 x 2 F ( n − 2 )
然后我们构造的一元二次方程就派上用场了!
根据韦达定理,对于一个一元二次方程 ax2+bx+c=0 a x 2 + b x + c = 0 的两个解 x1,2 x 1 , 2 满足: x1+x2=ba,x1x2=ca x 1 + x 2 = − b a , x 1 x 2 = c a
所以 F(n)=bF(n1)+db22F(n2) F ( n ) = b F ( n − 1 ) + d − b 2 2 F ( n − 2 )
其中 F(0)=2,F(1)=b F ( 0 ) = 2 , F ( 1 ) = b
推到这里就是非常经典的的矩乘快速递推啦!
对于第二部分,
b2d<(b+1)2 ∵ b 2 ≤ d < ( b + 1 ) 2
b,dN ∵ b , d ∈ N
bd<b+1 ∴ b ≤ d < b + 1
bd2(1,0] ∴ b − d 2 ∈ ( − 1 , 0 ]
不难发现,当且仅当 n n 为奇数且d!=b时,这一部分对答案有 1 − 1 的贡献。所以我们判一下是否减 1 1 就行了。
有一个坑点,这个模数非常大,加起来可能会爆long long,所以我们加的时候要判一下它们的和是否小于 0 0
注意两个数相乘会爆long long,所以要用快速乘。
快速乘其实主要就是利用 long double l o n g   d o u b l e 的较高的精度,再利用我们小学学的一个东西(被除数减除数乘商等于余数),就可以在 O(1) O ( 1 ) 的时间内完成较大的数的乘法并取模。
如果有错在评论区吼一声哦!
代码:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=7528443412579576937ll;
ll b,d,n;
ll Add(ll x,ll y){
    return x+y>=mod||x+y<0?x+y-mod:x+y;
}
ll Minus(ll x,ll y){
    return x-y<0?x-y+mod:x-y;
}
ll Mul(ll x,ll y){
    ll d=(ll)(x*(long double)y/mod+0.5);
    return Minus(x*y,d*mod);
}
struct Matrix{
    ll a[2][2];
    ll *operator[](int b){
        return a[b];
    }
    friend Matrix operator*(Matrix A,Matrix B){
        Matrix ret;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++){
                ret[i][j]=0;
                for(int k=0;k<2;k++)
                    ret[i][j]=Add(ret[i][j],Mul(A[i][k],B[k][j]));
            }
        return ret;
    }
    Matrix operator*=(Matrix B){
        *this=*this*B;
        return *this;
    }
}A,B;
Matrix qpow(Matrix x,ll n){
    Matrix ret;
    ret[0][0]=ret[1][1]=1,ret[0][1]=ret[1][0]=0;
    while(n){
        if(n&1ll)
            ret*=x;
        x*=x;
        n>>=1ll;
    }
    return ret;
}
int main(){
    scanf("%lld%lld%lld",&b,&d,&n);
    if(!n){
        puts("1");
        return 0;
    }
    A[0][0]=b;
    A[0][1]=2;
    B[0][0]=b;
    B[0][1]=1;
    B[1][0]=(d-b*b)/4;
    A[1][0]=A[1][1]=B[1][1]=0;
    A*=qpow(B,n-1);
    printf("%lld",Minus(A[0][0],!(n&1ll)&&(d!=b*b)));
    return 0;
}
内容概要:本文详细介绍了施耐德M580系列PLC的存储结构、系统硬件架构、上电写入程序及CPU冗余特性。在存储结构方面,涵盖拓扑寻址、Device DDT远程寻址以及寄存器寻址三种方式,详细解释了不同类型的寻址方法及其应用场景。系统硬件架构部分,阐述了最小系统的构建要素,包括CPU、机架和模块的选择与配置,并介绍了常见的系统拓扑结构,如简单的机架间拓扑和远程子站以太网菊花链等。上电写入程序环节,说明了通过USB和以太网两种接口进行程序下载的具体步骤,特别是针对初次下载时IP地址的设置方法。最后,CPU冗余部分重点描述了热备功能的实现机制,包括IP通讯地址配置和热备拓扑结构。 适合人群:从事工业自动化领域工作的技术人员,特别是对PLC编程及系统集成有一定了解的工程师。 使用场景及目标:①帮助工程师理解施耐德M580系列PLC的寻址机制,以便更好地进行模块配置和编程;②指导工程师完成最小系统的搭建,优化系统拓扑结构的设计;③提供详细的上电写入程序指南,确保程序下载顺利进行;④解释CPU冗余的实现方式,提高系统的稳定性和可靠性。 其他说明:文中还涉及一些特殊模块的功能介绍,如定时器事件和Modbus串口通讯模块,这些内容有助于用户深入了解M580系列PLC的高级应用。此外,附录部分提供了远程子站和热备冗余系统的实物图片,便于用户直观理解相关概念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值