链接:https://ac.nowcoder.com/acm/contest/885/B
题意:给你X0,X1,a,b,n,mod。且Xn=a*Xn-1+b*Xn-2。求Xn%mod。
思路:
1.对于广义斐波那契数列,不同的mod,打表之后发现有循环节。而循环节函数又是一个积性函数,所以可以快速找出循环节,然后计算。
f(n)表示当mod=n时,循环节的长度。那么该积性函数,有以下性质:
(1)f(p)=(p-1)*(p+1)
(2)f(a,b)=f(a)*f(b)(a、b互质)
(3)f(a,b)=f(a)*b(a%b==0)
我们就可以把mod的所有质因子以及它的积性函数值乘起来(加这分别为sum1,sum2),用mod/sum1*sum2,一定是一个循环节的长度。
PS:佳神tql,%%%%%%%%%%%%%%。
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int M=1e6+10;
const int N = 2;
const int maxn = 1e6;
int tot;
LL prime[maxn+10];
bool vis[maxn+10];
LL a,b,c,d,e,MOD,len;
char n[M];
struct Matrix
{
LL m[N][N];
};
Matrix A,B;
Matrix I = {1, 0, 0, 1};
void get_prime()
{
tot=0;
for(int i=2;i<=maxn;i++)
{
if(!vis[i]) prime[++tot]=i;
for(int j=1;j<=tot&&(LL)prime[j]*i<=maxn;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
return ;
}
LL mul(LL a,LL b)
{
LL res=0;
while(b)
{
if(b&1) res=(res+a)%MOD;
a=(a+a)%MOD;
b>>=1;
}
return res;
}
LL mul1(LL a,LL b,LL MOD)
{
LL res=0;
while(b)
{
if(b&1) res=(res+a)%MOD;
a=(a+a)%MOD;
b>>=1;
}
return res;
}
Matrix multi(Matrix a,Matrix b)
{
Matrix c;
for(int i=0; i>= 1;
p = multi(p,p);
}
return ans;
}
LL quick_mod(LL a,LL b)
{
LL ans = 1;
a %= MOD;
while(b)
{
if(b & 1)
{
ans = mul(ans,a);
}
b >>= 1;
a = mul(a ,a);
}
return ans;
}
LL cal(LL x)
{
LL sum1=1,sum2=1,temp=x;
for(int i=1;i<=tot&&(LL)prime[i]*prime[i]<=x;i++)
{
if(x%prime[i]==0)
{
sum1*=prime[i];
sum2*=(prime[i]*prime[i]-1);
while(x%prime[i]==0)
{
x/=prime[i];
}
}
}
if(x>1)
{
sum1*=x;
sum2*=(x*x-1);
}
return temp/sum1*sum2;
}
int main()
{
get_prime();
while(~scanf("%lld%lld%lld%lld",&c,&d,&a,&b))
{
scanf("%s%lld",n+1,&MOD);
len=0;
LL nn=0;
A.m[0][0] = a;
A.m[0][1] = b;
A.m[1][0] = 1;
A.m[1][1] = 0;
len=cal(MOD);
for(int i=1;i<=strlen(n+1);i++)
{
nn=mul1(nn,10,len)+n[i]-'0';
if(nn>=len) nn-=len;
}
B.m[0][0] = a;
B.m[0][1] = b;
B.m[1][0] = 1;
B.m[1][1] = 0;
Matrix res=power(B,nn-1);
LL ans=(mul(res.m[0][0],d)+mul(res.m[0][1],c))%MOD;
printf("%lld\n",ans);
}
return 0;
}
2:
十进制快速幂:例如1555,也就是5个10^0相乘后,再乘以5个10^1,再乘以5个10^2,再乘以1个10^3。每次算出10^0,10^1,10^2,一直乘即可。不过这个卡时间,少用mod,尽量减少循环才能过。
#include
#define ll long long
using namespace std;
const int N=1e6+10;
struct mat
{
ll m[2][2];
//mat(){ m[0][0]=m[0][1]=m[1][0]=m[1][1]=0;}
}ans,temp,tmp,res;
ll x0,x1,a,b,mod;
char s[N];
ll mul(ll a,ll b)
{
ll res=0;
while(b)
{
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
mat mat_mul(mat a,mat b)
{
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
res.m[i][j]=0;
for(int k=0;k<2;k++)
res.m[i][j]=(res.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
}
return res;
}
int main(void)
{
int n,num;
scanf("%lld%lld%lld%lld%s%lld",&x0,&x1,&a,&b,s+1,&mod);
ans.m[0][0]=ans.m[1][1]=1;
temp.m[0][0]=a;
temp.m[0][1]=b;
temp.m[1][0]=1;
temp.m[1][1]=0;
n=strlen(s+1);
for(int i=n;i>=1;i--)
{
num=s[i]-'0';
for(int j=1;j<=num;j++)
ans=mat_mul(ans,temp);
tmp.m[0][0]=tmp.m[1][1]=1;
tmp.m[1][0]=tmp.m[0][1]=0;
for(int j=1;j<=10;j++)
tmp=mat_mul(tmp,temp);
temp=tmp;
}
printf("%lld\n",(ans.m[1][0]*x1+ans.m[1][1]*x0)%mod);
return 0;
}