题解 P5110 【块速递推】

一道不错的题,教会我好多新套路。

首先得到递推式的特征方程

x 2 − 233 x − 666 = 0 x ^ 2 - 233 x - 666=0 x2233x666=0

易得 x = 233 ± 13 337 2 x= \frac{233 \pm 13 \sqrt{337}}{2} x=2233±13337

设通项式 A n = a x 1 n + b x 2 n A_n=ax_1^n+bx_2^n An=ax1n+bx2n

因为 A 0 = 0 , A 1 = 1 A_0=0,A_1=1 A0=0,A1=1

所以

{ a + b = 0 a x 1 + b x 2 = 1 \begin{cases}\begin{array}{}a+b=0\\ax_1+bx_2=1\end{array}\end{cases} {a+b=0ax1+bx2=1

解得

{ a = 1 13 337 b = − 1 13 337 \begin{cases}\begin{array}{}a=\frac{1}{13\sqrt{337}}\\b=-\frac{1}{13\sqrt{337}}\end{array}\end{cases} {a=13337 1b=13337 1

于是得通项式 A n = 1 13 337 ( ( 233 + 13 337 2 ) n − ( 233 − 13 337 2 ) n ) A_n=\dfrac{1}{13\sqrt{337}}((\dfrac{233+13 \sqrt{337}}{2})^n-(\dfrac{233-13 \sqrt{337}}{2})^n) An=13337 1((2233+13337 )n(223313337 )n)

B S G S BSGS BSGS求二次剩余,不难解得在 m o d    1000000007 \mod{1000000007} mod1000000007 时,通项式为

A n ≡ 233230706 ( 9415303 5 n − 90584720 5 n ) ( m o d    1000000007 ) A_n \equiv 233230706 ( 94153035 ^ n - 905847205 ^ n )(\mod 1000000007) An233230706(94153035n905847205n)(mod1000000007)

考虑到快速幂带 l o g log log,无法通过本题。。。

然而因为模数为奇质数

于是根据费马小定理,显然任意数的幂都有长度为 1000000006 1000000006 1000000006的循环节,因此指数被缩小到 1000000006 1000000006 1000000006的范围

又因为底数与模数确定

所以我们可以选取一个与 1000000006 \sqrt{1000000006} 1000000006 同阶的数 m m m,预处理出 x 0 , x 1 , . . . , x m − 1 x^0,x^1,...,x^ { m - 1 } x0,x1,...,xm1 x 0 , x m , . . . , x m 2 x^0,x^m,...,x^{m^2} x0,xm,...,xm2

然后对于每一个询问 x k x^k xk O ( 1 ) O(1) O(1) x ⌊ k / m ⌋ × x k m o d    m x^{\lfloor k / m \rfloor} \times x^{k\mod{m}} xk/m×xkmodm即可

于是此题得解。。。

#include<cstdio>
const int P=1000000007;
const int a=233230706,b1=94153035,b2=905847205;
const int BLOCK_SIZE=32768;

int hbp1[BLOCK_SIZE],lbp1[BLOCK_SIZE];
int hbp2[BLOCK_SIZE],lbp2[BLOCK_SIZE];

void init()
{
    lbp1[0]=1;
    for(int i=1;i<BLOCK_SIZE;++i)lbp1[i]=(long long)lbp1[i-1]*b1%P;
    hbp1[0]=1;
    hbp1[1]=(long long)lbp1[BLOCK_SIZE-1]*b1%P;
    for(int i=2;i<BLOCK_SIZE;++i)hbp1[i]=(long long)hbp1[i-1]*hbp1[1]%P;
    lbp2[0]=1;
    for(int i=1;i<BLOCK_SIZE;++i)lbp2[i]=(long long)lbp2[i-1]*b2%P;
    hbp2[0]=1;
    hbp2[1]=(long long)lbp2[BLOCK_SIZE-1]*b2%P;
    for(int i=2;i<BLOCK_SIZE;++i)hbp2[i]=(long long)hbp2[i-1]*hbp2[1]%P;
}
int power1(int k)
{
    return (long long)hbp1[k/BLOCK_SIZE]*lbp1[k%BLOCK_SIZE]%P;
}
int power2(int k)
{
    return (long long)hbp2[k/BLOCK_SIZE]*lbp2[k%BLOCK_SIZE]%P;
}

namespace Mker
{
    unsigned long long SA,SB,SC;
    void init(){scanf("%llu%llu%llu",&SA,&SB,&SC);}
    unsigned long long rand()
    {
        SA^=SA<<32,SA^=SA>>13,SA^=SA<<1;
        unsigned long long t=SA;
        SA=SB,SB=SC,SC^=t^SA;return SC;
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    init();
    Mker::init();
    int res=0;
    while(T--)
    {
        int n=Mker::rand()%1000000006;
        res^=(long long)a*(power1(n)-power2(n)+P)%P;
    }
    printf("%d",res);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值