• 洛谷 P5136 题解


    P5136 sequence 题解

    发现要求的是带根号的,考虑二次剩余共轭。

    参考 [JLOI2015]有意义的字符串

    \(p=\frac{1+\sqrt{5}}{2},q=\frac{1-\sqrt{5}}{2}\),显然有:

    1. \(p+q=1\)
    2. \(pq=-1\)

    对于方程 \(x^2-x-1\)\(p,q\) 即为方程两根。

    直接求 \(p^n\) 较为困难,考虑记 \(f_n=p^n+q^n\)。有:

    \[\begin{array}{c} p^n+q^n=(p^{n-1}+q^{n-1})(p+q)-(p^{n-2}+q^{n-2})pq\\ \Updownarrow\\ f_n=f_{n-1}+f_{n-2} \end{array} \]

    根据这个递推式和上面的特征方程,发现这是一个斐波那契数列,首项可以手推:\(f_0=p^0+q^0=2,f_1=p+q=1\)

    注意到最后答案应该是 \(f_n-q^n\),发现 \(\left|q\right|<\overline\phi\),根据上取整的性质,有 \(\texttt{ans}=f_n+[n\text { is odd}]\)

    至此,可以用矩阵快速幂在 \(\Theta(T\log n)\) 的时间复杂度内解决本题。

    不过根据斐波那契循环节的常识,本题还能继续优化。

    发现模数 \(998244353\equiv3\pmod{5}\),则循环节为 \(2\times(998244353+1)\)(详见 斐波那契循环节)。

    至此,可以通过 \(n\le10^{114514+1919810}\) 的数据了,复杂度与 \(n\) 无关(除读入)。

    时间复杂度 \(\Theta(T\log 998244353)=\Theta(T)\)(雾

    时间复杂度 \(\Theta(T\log p)\)

    还可以继续拓展。若 \(p\) 不为质数,则可以继续分解(详见 斐波那契循环节)求出循环节 \(G\),由于 \(G\le 6p\),时间复杂度 \(\Theta(\sqrt{p}+\log p)\sim\Theta(T\log p)\)

    更进一步,发现有多组询问,我们考虑降低一次查询的复杂度。

    类似 BSGS 的思想,我们可以对矩阵幂分块,记转移矩阵为 \(P\)\(S = \sqrt{p}\),用哈希表记录 \(P^S,P^{2S},P^{3S},\cdots\)\(P,P^2,\cdots,P^{S-1}\),求解时只需完成三个矩阵相互乘即可。

    时间复杂度 \(\Theta(\sqrt{p}+\log p)\sim\Theta(T)\)

    CODE

    // Problem: P5136 sequence
    // From: Luogu
    // URL: https://www.luogu.com.cn/problem/P5136
    // Time: 2022-03-06 15:59
    // Author: lingfunny
    
    #include <bits/stdc++.h>
    #include<ext/pb_ds/assoc_container.hpp>
    #include<ext/pb_ds/hash_policy.hpp>
    using namespace __gnu_pbds;
    #define LL long long
    const int mod = 998244353, loop = (mod+1)<<1, S = ceil(sqrt(loop));
    using namespace std;
    
    int tt, n;
    inline int mul(int x, int y) { return (LL)x*y%mod; }
    
    struct matrix {
    	int a[2][2], n, m;
    	inline matrix operator * (const matrix& rhs) const {
    		matrix res;
    		res.n = n, res.m = rhs.m;
    		for(int i = 0; i < n; ++i)
    		for(int j = 0; j < rhs.m; ++j) {
    			res.a[i][j] = 0;
    			for(int k = 0; k < m; ++k)
    			(res.a[i][j] += mul(a[i][k], rhs.a[k][j])) %= mod;
    		}
    		return res;
    	}
    } A = { { {2, 1}, {0, 0} }, 1, 2 }, ls[S+5];
    const matrix P = { { {0, 1}, {1, 1} }, 2, 2 };
    gp_hash_table <int, matrix> gs;
    inline void init() {
    	matrix x = {{{1,0},{0,1}},2,2}, y;
    	gs[0] = x;
    	for(int i = 0; i < S; ++i) {
    		ls[i] = x;
    		x = x * P;
    	}
    	y = x;
    	for(int i = 1; i <= S; ++i) {
    		gs[i] = y;
    		y = y * x;
    	}
    }
    #define GC getchar()
    inline int read() {
    	unsigned x = 0; char ch = GC;
    	while(ch < '0') ch = GC;
    	while('0' <= ch) { x = ((x<<1) + ((LL)x<<3) + (ch^48)) % loop; ch = GC; }
    	return x;
    }
    
    signed main() {
    	init();
    	tt = read();
    	while(tt--) {
    		n = read();
    		A.a[0][0] = 2; A.a[0][1] = 1;
    		A = A * (gs[n/S] * ls[n%S]);
    		printf("%d\n", (A.a[0][0]+(n&1))%mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JPA + EclipseLink + SAP云平台 = 运行在云端的数据库应用
    Java实现 LeetCode 500 键盘行
    Java实现 LeetCode 500 键盘行
    Java实现 LeetCode 498 对角线遍历
    Java实现 LeetCode 498 对角线遍历
    Java实现 LeetCode 498 对角线遍历
    Java实现 LeetCode 496 下一个更大元素 I
    Java实现 LeetCode 496 下一个更大元素 I
    Java实现 LeetCode 496 下一个更大元素 I
    Java实现 LeetCode 495 提莫攻击
  • 原文地址:https://www.cnblogs.com/lingfunny/p/16361126.html
Copyright © 2020-2023  润新知