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)=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(2\leq i\leq 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),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;
}
矩阵快速幂+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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值