2019 南昌 ICPC网络赛 H The Nth Item (矩阵快速幂/二次剩余+记忆化)

题目连接

原题描述

For a series:

egin{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)=3F(n1)+2F(n2),(n2)

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(2leq ileq Q)Ni(2iQ) is defined as the xor of the previous N_{i-1}Ni1 and the square of the previous answer A_{i-1}Ai1. 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 (33)=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  Q107,0  N1018. 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),ngeq 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;
}
矩阵快速幂+unordered_map记忆化

$赛后看了题解,了解了一点点二次剩余,于是回到上面推出的通项公式$

$先求出 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;
}
二次剩余+unordered_map

广义斐波那契循环节。。upt




原文地址:https://www.cnblogs.com/mooleetzi/p/11492237.html