zoukankan      html  css  js  c++  java
  • 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

    
    


  • 相关阅读:
    spring bean的生命周期
    02-MySQL主要配置文件
    01-MySQL Linux安装
    spring自动装配
    JVMGC+Spring Boot生产部署和调参优化
    java面试-生产环境出现CPU占用过高,谈谈你的分析思路和定位
    java面试-G1垃圾收集器
    java面试-垃圾回收器谈谈你的理解
    java面试-谈谈你对OOM的理解
    RPC介绍以及编程
  • 原文地址:https://www.cnblogs.com/mooleetzi/p/11492237.html
Copyright © 2011-2022 走看看