【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;
}
内容概要:本文详细介绍了QY20B型汽车起重机液压系统的设计过程,涵盖其背景、发展史、主要运动机构及其液压回路设计。文章首先概述了汽车起重机的分类和发展历程,强调了液压技术在现代起重机中的重要性。接着,文章深入分析了QY20B型汽车起重机的五大主要运动机构(支腿、回转、伸缩、变幅、起升)的工作原理及相应的液压回路设计。每个回路的设计均考虑了性能要求、功能实现及工作原理,确保系统稳定可靠。此外,文章还详细计算了支腿油缸的受力、液压元件的选择及液压系统的性能验算,确保设计的可行性和安全性。 适合人群:从事工程机械设计、液压系统设计及相关领域的工程师和技术人员,以及对起重机技术感兴趣的高等院校学生和研究人员。 使用场景及目标:①为从事汽车起重机液压系统设计的工程师提供详细的参考案例;②帮助技术人员理解和掌握液压系统设计的关键技术和计算方法;③为高等院校学生提供学习和研究起重机液压系统设计的实用资料。 其他说明:本文不仅提供了详细的液压系统设计过程,还结合了实际工程应用,确保设计的实用性和可靠性。文中引用了大量参考文献,确保设计依据的科学性和权威性。阅读本文有助于读者深入了解汽车起重机液压系统的设计原理和实现方法,为实际工程应用提供有力支持。
### BZOJ1461 字符串匹配 题解 针对BZOJ1461字符串匹配问题,解决方法涉及到了KMP算法以及树状数组的应用。对于此类问题,朴素的算法无法满足时间效率的要求,因为其复杂度可能高达O(ML²),其中M代表模式串的数量,L为平均长度[^2]。 为了提高效率,在这个问题中采用了更先进的技术组合——即利用KMP算法来预处理模式串,并通过构建失配树(也称为失败指针),使得可以在主串上高效地滑动窗口并检测多个模式串的存在情况。具体来说: - **前缀函数与KMP准备阶段**:先对每一个给定的模式串执行一次KMP算法中的pre_kmp操作,得到各个模式串对应的next数组。 - **建立失配树结构**:基于所有模式串共同构成的一棵Trie树基础上进一步扩展成带有失配链接指向的AC自动机形式;当遇到某个节点不存在对应字符转移路径时,则沿用该处失配链路直至找到合适的目标或者回到根部重新开始尝试其他分支。 - **查询过程**:遍历整个待查文本序列的同时维护当前状态处于哪一层级下的哪个子结点之中,每当成功匹配到完整的单词就更新计数值至相应位置上的f_i变量里去记录下这一事实。 下面是简化版Python代码片段用于说明上述逻辑框架: ```python from collections import defaultdict def build_ac_automaton(patterns): trie = {} fail = [None]*len(patterns) # 构建 Trie 树 for i,pattern in enumerate(patterns): node = trie for char in pattern: if char not in node: node[char]={} node=node[char] node['#']=i queue=[trie] while queue: current=queue.pop() for key,value in list(current.items()): if isinstance(value,int):continue if key=='#': continue parent=current[key] p=fail[current is trie and 0 or id(current)] while True: next_p=p and p.get(key,None) if next_p:break elif p==0: value['fail']=trie break else:p=fail[id(p)] if 'fail'not in value:value['fail']=next_p queue.append(parent) return trie,fail def solve(text, patterns): n=len(text) m=len(patterns) f=[defaultdict(int)for _in range(n)] ac_trie,_=build_ac_automaton(patterns) state=ac_trie for idx,char in enumerate(text+'$',start=-1): while True: trans=state.get(char,state.get('#',{}).get('fail')) if trans!=None: state=trans break elif '#'in state: state[state['#']['fail']] else: state=ac_trie cur_state=state while cur_state!={}and'#'in cur_state: matched_pattern_idx=cur_state['#'] f[idx][matched_pattern_idx]+=1 cur_state=cur_state['fail'] result=[] for i in range(len(f)-1): row=list(f[i].values()) if any(row): result.extend([sum((row[:j+1]))for j,x in enumerate(row[::-1])if x>0]) return sum(result) patterns=["ab","bc"] text="abc" print(solve(text,text)) #[^4] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值