2019牛客暑期多校训练营(第五场) B generator 1(积性函数+循环节或十进制快速幂模板)

链接: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;	
} 

 

你可能感兴趣的:(=====结论=====,=====数论=====,=====模板=====)