2019 南昌 ICPC网络赛 H The Nth Item (矩阵快速幂/二次剩余+记忆化)
原题描述
For a series:
\begin{gathered} F(0) = 0,F(1) = 1\\ F(n) = 3*F(n-1)+2*F(n-2),(n \geq 2) \end{gathered}F(0)=0,F(1)=1F(n)=3∗F(n−1)+2∗F(n−2),(n≥2)
We have some queries. For each query NN, the answer AA is the value F(N)F(N) modulo 998244353998244353.
Moreover, the input data is given in the form of encryption, only the number of queries QQ and the first query N_1N1 are given. For the others, the query N_i(2\leq i\leq Q)Ni(2≤i≤Q) is defined as the xor of the previous N_{i-1}Ni−1 and the square of the previous answer A_{i-1}Ai−1. For example, if the first query N_1N1 is 22, the answer A_1A1 is 33, then the second query N_2N2 is 2 \ xor \ ( 3*3)=112 xor (3∗3)=11.
Finally, you don't need to output all the answers for every query, you just need to output the xor of each query's answer A_1\ xor\ A_2 ... xor\ A_QA1 xor A2...xor AQ.
Input
The input contains two integers, Q, NQ,N, 1\ \leq \ Q \leq 10^7,0\ \leq\ N \leq 10^{18}1 ≤ Q≤107,0 ≤ N≤1018. QQ representing the number of queries and NN representing the first query.
Output
An integer representing the final answer.
Solution
题目中的式子$F(n)=3*F(n-1)+2*F(n-2),n\geq 2$是一个二阶常系数线性递推式,可以用特征方程求解通项
$特征方程为:x^2-3x-2=0,x_1=\frac{3+\sqrt{17}}{2},x_2=\frac{3-\sqrt{17}}{2},令F(n)=c_1{x_1}^n+c_2{x_2}^n$
$代入F(0)=0,F(1)=1,c_1=\frac{\sqrt{17}}{17},c_2=-c_1$
$得出式子$ $$F(n)=\frac{\sqrt{17}}{17}[{(\frac{3+\sqrt{17}}{2})}^n-{(\frac{3-\sqrt{17}}{2})}^n]$$
好的到了这里我就没了,并不会二次剩余,然后我开始莽,写了一发矩阵快速幂+unordered_map记忆化
!!!就过了,xswl
#include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <map> #include <queue> #include <set> #include <stack> #if __cplusplus >= 201103L #include <unordered_map> #include <unordered_set> #endif #include <vector> #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r #define LONG_LONG_MAX 9223372036854775807LL #define ll LL using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair<int, int> P; int n, m, k; const int maxn = 1e5 + 10; const int mod = 998244353; template <class T> inline T read() { int f = 1; T ret = 0; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { ret = (ret << 1) + (ret << 3) + ch - '0'; ch = getchar(); } ret *= f; return ret; } template <class T> inline void write(T n) { if (n < 0) { putchar('-'); n = -n; } if (n >= 10) { write(n / 10); } putchar(n % 10 + '0'); } template <class T> inline void writeln(const T &n) { write(n); puts(""); } struct mat { ll tmp[2][2]; mat() { for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) tmp[i][j] = 0; } }; mat mul(const mat &a, const mat &b) { mat res; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) res.tmp[i][j] = (res.tmp[i][j] + a.tmp[i][k] * b.tmp[k][j] % mod) % mod; return res; } mat qpow(mat a, ll n) { mat res; res.tmp[0][0] = res.tmp[1][1] = 1; while (n) { if (n & 1) res = mul(res, a); a = mul(a, a); n >>= 1; } return res; } unordered_map<ll, ll> mp; inline ll cal(ll n) { if (mp.count(n)) return mp[n]; mat m; m.tmp[0][0] = 3, m.tmp[0][1] = 2; m.tmp[1][0] = 1; m = qpow(m, n - 1); return mp[n] = m.tmp[0][0] % mod; } void init() { ll a = 0, b = 1; for (int i = 0; i < 1e6; i++) { mp[i] = a; ll t = b; b = (3 * b % mod + 2 * a % mod) % mod; a = t; } } int main(int argc, char const *argv[]) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif init(); ll n = read<ll>(), q = read<ll>(); ll pre = q, res = 0, tres = 0; for (int i = 0; i < n; i++) { pre ^= (tres * tres); tres = cal(pre); res ^= tres; } writeln(res); return 0; }
$赛后看了题解,了解了一点点二次剩余,于是回到上面推出的通项公式$
$先求出 \sqrt{17} 在模998244353意义下的二次剩余\sqrt{17}=473844410,以及inv(\sqrt{17})=559329360 $
$将其代入F(n)得到$
$$F(n)=559329360*(262199973^n-736044383^n)$$
题解后续优化菜鸡没看明白,来日再更。得到上式加了一个记忆化也过了,不过计蒜客看不了运行时间qaq
#include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iostream> #include <map> #include <queue> #include <set> #include <stack> #if __cplusplus >= 201103L #include <unordered_map> #include <unordered_set> #endif #include <vector> #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r #define LONG_LONG_MAX 9223372036854775807LL #define ll LL using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair<int, int> P; int n, m, k; const int maxn = 1e5 + 10; const int mod = 998244353; template <class T> inline T read() { int f = 1; T ret = 0; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { ret = (ret << 1) + (ret << 3) + ch - '0'; ch = getchar(); } ret *= f; return ret; } template <class T> inline void write(T n) { if (n < 0) { putchar('-'); n = -n; } if (n >= 10) { write(n / 10); } putchar(n % 10 + '0'); } template <class T> inline void writeln(const T &n) { write(n); puts(""); } ll qpow(ll a, ll b) { ll res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } struct num { ll x, y; }; ll w; num mul(num a, num b, ll p) { num ans = {0, 0}; ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p; ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p; return ans; } ll powwR(ll a, ll b, ll p) { ll ans = 1; while (b) { if (b & 1) ans = 1ll * ans % p * a % p; a = a % p * a % p; b >>= 1; } return ans % p; } ll powwi(num a, ll b, ll p) { num ans = {1, 0}; while (b) { if (b & 1) ans = mul(ans, a, p); a = mul(a, a, p); b >>= 1; } return ans.x % p; } ll solve(ll n, ll p) { n %= p; if (p == 2) return n; if (powwR(n, (p - 1) / 2, p) == p - 1) return -1; //不存在 ll a; while (1) { a = rand() % p; w = ((a * a % p - n) % p + p) % p; if (powwR(w, (p - 1) / 2, p) == p - 1) break; } num x = {a, 1}; return powwi(x, (p + 1) / 2, p); } const ll p1 = 262199973, p2 = 736044383; const ll sqrt17 = 473844410, invsqrt17 = 559329360; unordered_map<ll, ll> mp; ll cal(ll n) { if (mp.count(n)) return mp[n]; return mp[n] = (qpow(p1, n) - qpow(p2, n) + mod) % mod * invsqrt17 % mod; } int main(int argc, char const *argv[]) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif srand(time(0)); int q = read<int>(); ll n = read<ll>(); ll pre = 0, res = 0; for (int i = 0; i < q; i++) { n ^= (pre * pre); pre = cal(n); res ^= pre; } writeln(res); return 0; }
广义斐波那契循环节。。upt