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 <bits/stdc++.h>
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<<ans<<endl;
return 0;
}
方法二:
就是题解啦~凭感觉理解了一下咳咳。
首先第一步我就不会,求通项公式什么的……
会了我也不太能反映过来用二次剩余,刚学还不太会用
然后我也想不到那个优化emmm
我就解释一下那个优化吧,嗯,我大概看懂了,类似
结合题解,假设括号里的数为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) ).
妈耶好机智,学到了,下次还是想不到。
没有代码,我就脑内意会了一下。