[超级矩阵快速幂]2019南昌ICPC网络赛 H The Nth Item

https://nanti.jisuanke.com/t/41355

题意:求给出的广义斐波那契数列%998244353的第n项,n<=1e18

方法一:

给一个n,我们可以把它变成x进制,x取比较大的时候位数就会比较小啦(每一位的数字可能比较大了就,比如16进制1位顶2进制4位这个亚子)此处把每一位的数字称为这位的系数吧emmm。

比如说只有3位的时候,我们只需要预处理出每一位的权重w和该位系数为x时对应的x^w的值。这样对于每一个n,它变成几位我就算几次嘛,常数也阔以比较小ovo。就是要注意一下平衡这个位数和系数……队友取的进制很有点神奇->1260000

另外虽然保证n<=1e18,其实指的是第一个n在这个范围内,后续的是有可能超出的QWQ但是不会超过2e18的嘛

#include 
using namespace std;
#define ll long long
#define db double
#define pi acos(-1)
#define p 998244353
struct node
{
    ll x[2][2];
}f[3][1260000],g,yuan,mat;
node operator * (const node x,const node y)
{
    node c;
    for (int i=0;i<2;++i)
    for (int j=0;j<2;++j)
        c.x[i][j]=0;
        for (int k=0;k<2;++k)
    for (int i=0;i<2;++i)
    for (int j=0;j<2;++j)
    {
            (c.x[i][j]+=x.x[i][k]*y.x[k][j])%=p;
    }
    return c;
}
node power(const node x,ll m)
{
    node s1=yuan,s2=x;
    while (m)
    {
        if (m&1) s1=s1*s2;
        m>>=1;
        s2=s2*s2;
    }
    return s1;
}
ll calc(ll n)
{
    if (n<0) return 0;
    node s=yuan;
    for (int i=0;i<3 && n;++i)
    {
        ll t=n%1260000;
        s=s*f[i][t];
        n/=1260000;
    }
    return s.x[0][0];
}
int main()
{
    g.x[0][0]=3;g.x[0][1]=2;
    g.x[1][0]=1;g.x[1][1]=0;
    yuan.x[0][0]=yuan.x[1][1]=1;
    ll t=1;
    for (int i=0;i<3;++i,t*=1260000)
    {
        f[i][0]=yuan;
        mat=power(g,t);
        for (int j=1;j<1260000;++j)
            f[i][j]=f[i][j-1]*mat;
    }
    int Q;
    ll n;
    cin>>Q>>n;
    ll ans=0,res;
    while (Q--)
    {
        res=calc(n-1);
        ans^=res;
        n=n^(res*res);
    }
    cout<

方法二:

就是题解啦~凭感觉理解了一下咳咳。

首先第一步我就不会,求通项公式什么的……

会了我也不太能反映过来用二次剩余,刚学还不太会用

然后我也想不到那个优化emmm

我就解释一下那个优化吧,嗯,我大概看懂了,类似

[超级矩阵快速幂]2019南昌ICPC网络赛 H The Nth Item_第1张图片

结合题解,假设括号里的数为x。

现在要求的就是n很大的x^n。

如果我预处理出x^y以及x^(y*sqrt(1e9))的值,其中y在[0,sqrt(1e9)]范围内。

则x^n= x^( ( n/sqrt(1e9) )*sqrt(1e9)+n%sqrt(1e9) ).

妈耶好机智,学到了,下次还是想不到。

没有代码,我就脑内意会了一下。

你可能感兴趣的:(数论,斐波那契,二次剩余,矩阵快速幂加速,好题,数论,二次剩余)