• @loj



    @description@

    B 君有两个好朋友,他们叫宁宁和冉冉。有一天,冉冉遇到了一个有趣的题目:输入 (b, d, n),求:

    [lfloor(frac{b + sqrt{d}}{2})^n floor mod 7528443412579576937 ]

    原题戳我查看owo

    @solution@

    这道题的思路最早可以追溯到这一道经典题目吧。。。

    注意到数据范围满足 (b^2 le d < (b + 1)^2)(虽然样例不满足),这意味着 (|frac{b - sqrt{d}}{2}| < 1)

    利用共轭的性质。如果我们求出 (f(n) = (frac{b + sqrt{d}}{2})^n + (frac{b - sqrt{d}}{2})^n) 的整数部分,则题目所要的东西实际上 = f(n) 或 f(n) - 1。

    尝试递推。看到分母除 2,想到二次方程的求根公式。

    (p = (frac{b + sqrt{d}}{2}), q = (frac{b - sqrt{d}}{2})),则 p, q 应该为方程 (x^2 - bx + frac{b^2 - d}{4} = 0) 两根。

    也就说有 (p^2 = bp - frac{b^2 - d}{4}, q^2 = bq - frac{b^2 - d}{4})

    然后就可以带入 f(n) 的式子里面降次,得到 f(n) 与 f(n-1),f(n-2) 的递推式子。矩阵幂即可。

    -------分割线--------

    当然还有另一种看起来更nb的推导方法。

    我们构造 f(n) 的生成函数,记 (F(x) = sum_{i=0}f(i)x^i)。则:

    [F(x) = sum_{i=0}(frac{b + sqrt{d}}{2})^ix^i + sum_{i=0}(frac{b - sqrt{d}}{2})^ix^i \ = frac{1}{1 - (frac{b + sqrt{d}}{2})x} + frac{1}{1 - (frac{b - sqrt{d}}{2})x} \ = frac{2 - bx}{frac{b^2 - d}{4}x^2 - bx + 1}]

    再对等式进行变形:

    [(frac{b^2 - d}{4}x^2 - bx + 1)F(x) = 2 - bx \ F(x) = -frac{b^2 - d}{4}x^2F(x) + bxF(x) + 2 - bx ]

    对应项系数比较,除 0 和 1 以外,有 (f(n) = -frac{b^2 - d}{4}f(n-2) + bf(n-1))。得到了一样的结果。

    其实这就是斐波那契的通项公式的逆推导过程。

    @accepted code@

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef unsigned long long ull;
    
    const ull MOD = 7528443412579576937LL;
    ull add(ull A, ull B) {
    	return (A + B >= MOD ? A + B - MOD : A + B);
    }
    ull mul(ull A, ull B) {
    	ull C = 0;
    	for(ull i=B;i;i>>=1,A=add(A,A))
    		if( i & 1 ) C = add(C, A);
    	return C;
    }
    
    ull A[2][2], R[2][2], C[2][2];
    void mul(ull B[][2]) {
    	C[0][0] = add(mul(B[0][0], A[0][0]), mul(B[0][1], A[1][0]));
    	C[0][1] = add(mul(B[0][0], A[0][1]), mul(B[0][1], A[1][1]));
    	C[1][0] = add(mul(B[1][0], A[0][0]), mul(B[1][1], A[1][0]));
    	C[1][1] = add(mul(B[1][0], A[0][1]), mul(B[1][1], A[1][1]));
    	B[0][0] = C[0][0], B[0][1] = C[0][1], B[1][0] = C[1][0], B[1][1] = C[1][1];
    }
    
    int main() {
    	ull b, d, n;
    	cin >> b >> d >> n;
    	A[0][0] = b, A[0][1] = (d - b*b) / 4;
    	A[1][0] = 1, A[1][1] = 0;
    	R[0][0] = R[1][1] = 1, R[1][0] = R[0][1] = 0;
    	for(ull i=n;i;i>>=1,mul(A))
    		if( i & 1 ) mul(R);
    	ull res = add(mul(b, R[1][0]), mul(2, R[1][1]));
    	if( n % 2 == 0 ) {
    		res = (res == 0 ? MOD - 1 : res - 1);
    	}
    	cout << res << endl;
    } 
    

    @details@

    有一个小疑问:照这样推导下来 (f(n) = (frac{b + sqrt{d}}{2})^n + (frac{b - sqrt{d}}{2})^n) 一定为整数。

    可是为什么。可以证明这一点吗?

  • 相关阅读:
    视图&索引&序列
    PL/SQL语言基础
    C#实现递归矩阵连乘(动态规划的递归自顶向下,非递归自地向上)
    JS 第五课
    请问,小丽的鞋子到底是什么颜色的?
    用10!来回顾 PL/SQL语言基础 && 标准异常名
    SELECT 查询—子查询
    备份和恢复
    JS 第六课
    Linux学习之二Linux系统的目录结构
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12116685.html
Copyright © 2020-2023  润新知