2019-南昌网络赛 The Nth Item(矩阵快速幂+记忆化||找规律)

For a series FF:

\displaystyle \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.

样例输入复制

17 473844410

样例输出复制

903193081

时限1s,虽然普通矩阵快速幂肯定过不了,但是还是交了一发试了一下

后来也想到用记忆化优化,不过忽视了取模的过程中n并不是越来越大的,,并且时间也不够了,于是这个题就凉了

据说正解是找规律,先挖个坑。

下面是加入map记忆化的676ms AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2;
const ll mod=998244353;

inline ll read()///没错 快读是偷来的
{
    ll x=0;
    char c=0;
    c=getchar();
    while(isdigit(c))
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x;
}

struct mat
{
    ll a[N][N];
};

//ll qmul(ll a,ll b)///哦对 还有这个问题 我也不知道为什么加上快速积就会超时 难道是因为数据本来没有很大 多此一举???? 请教路过的大佬 orz
//{
//    ll ans=0,res=a;
//    while(b)
//    {
//        if(b&1)
//            ans=(ans+res);
//        res=(res+res);
//        b>>=1;
//    }
//    return ans;
//}

mat mat_mul(mat x,mat y)
{
    mat res;
    memset(res.a,0,sizeof(res.a));
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            for(int k=0; k<2; k++)
                res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
        }
    }
    return res;
}

ll mat_pow(ll n)
{
    if(n<0)
    {
        return 0;
    }
    mat c,res;
    c.a[0][0]=3;
    c.a[0][1]=2;
    c.a[1][0]=1;
    c.a[1][1]=0;
    memset(res.a,0,sizeof(res.a));
    for(int i=0; i<2; i++)
        res.a[i][i]=1;
    while(n)
    {
        if(n&1)
            res=mat_mul(res,c);
        c=mat_mul(c,c);
        n=n>>1;
    }
    return res.a[0][0];
}

int main()
{
    int q;
    ll n;
    q=read();
    n=read();
    map<ll,ll>mp;
    mp.clear();
    ll ans=0;
    ll cnt=n;
    mp[0]=0;
    mp[1]=1;
    for(int i=1; i<=q; i++)
    {
        if(mp.count(cnt)!=0)
        {
            ans^=mp[cnt];
            cnt^=(mp[cnt]*mp[cnt]);
        }
        else
        {
            ll tmp=mat_pow(cnt-1);
            mp[cnt]=tmp;
            ans^=tmp;
            cnt^=(tmp*tmp);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值