【2019 南昌网络赛】The Nth Item(分块)

For a series F:

F ( 0 ) = 0 , F ( 1 ) = 1 F ( n ) = 3 ∗ F ( n − 1 ) + 2 ∗ F ( n − 2 ) , ( n ≥ 2 ) \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)=3F(n1)+2F(n2),(n2)

We have some queries. For each query N, the answer A is the value F(N) modulo 998244353.

Moreover, the input data is given in the form of encryption, only the number of queries Q and the first query N 1 N_1 N1are given. For the others, the query N i ( 2 ≤ i ≤ Q ) N_i(2\leq i\leq Q) Ni(2iQ)is defined as the xor of the previous N i − 1 N_{i-1} Ni1and the square of the previous answer A i − 1 A_{i-1} Ai1 For example, if the first query N 1 N_1 N1is 2, the answer A 1 A_1 A1 is 3, then the second query $N_2 $is 2   x o r   ( 3 ∗ 3 ) = 11 2 \ xor \ ( 3*3)=11 2 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   x o r   A 2 . . . x o r   A Q A_1\ xor\ A_2 ... xor\ A_Q A1 xor A2...xor AQ
.

Input
The input contains two integers, Q,N, 1   ≤   Q ≤ 1 0 7 , 0   ≤   N ≤ 1 0 18 1\ \leq \ Q \leq 10^7,0\ \leq\ N \leq 10^{18} 1  Q107,0  N1018
Q representing the number of queries and N representing the first query.

Output:
An integer representing the final answer.

样例输入
17 473844410
样例输出
903193081

我连二次剩余直接用板子都敲出来了,以为可以优化矩阵的常数,没想过用分块,还是分块大法好
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define mod 998244353
using namespace std;
const int maxx = 200005;
struct M
{
    ll m[2][2];
    friend M operator *(M x1,M x2)
    {
        M tmp;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
            {
                tmp.m[i][j]=x1.m[i][0]*x2.m[0][j]%mod+x1.m[i][1]*x2.m[1][j]%mod;
                if(tmp.m[i][j]>=mod)tmp.m[i][j]-=mod;
            }
        return tmp;
    }
};
M P(M a,ll b)
{
    M ans={1,0,0,1};
    while(b)
    {
        if(b&1)ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}
int per=499122176;
M block[5000005];
M res[1005];
ll f(int x)
{
    M ans=block[x/100]*res[x%100];
    return ans.m[1][0];
}
ll n,q;
int main()
{
    res[0]={1,0,0,1};
    res[1]={3,2,1,0};
    for(int i=2;i<=100;i++)res[i]=res[i-1]*res[1];

    block[0]=res[0];
    for(int i=1;i<=5e6;i++)block[i]=block[i-1]*res[100];
    //for(int i=1;i<100;i++)cout<<i<<" "<<f(i)<<endl;
    cin>>q>>n;
    ll last=n;
    ll ans=0;

    while(q--)
    {
        ll now=f(last%per);
        ans^=now;
        //cout<<now<<endl;
        last=last^(now*now);
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值