【2018/08/30测试T2】【SDOJ 3739】k-斐波那契

【题目】

题目描述:

输入格式:

一行两个整数 n,P

输出格式:

从小到大输出可能的 k,若不存在,输出 None

样例数据:

输入

5 5

输出

2

备注:

【样例解释】 

f[0] = 2
f[1] = 2
f[2] = 4
f[3] = 6 mod 5 = 1
f[4] = 5 mod 5 = 0
f[5] = 1

【数据范围】

30% 的数据保证 n , P ≤ 1000 
100% 的数据保证 n , P ≤ 10^{9}

【分析】

首先呢,k-斐波那契数列其实和普通的斐波那契数列是一样的,只不过每一项都乘了一个 k

那么我们现在的问题有两个:

  1. 如何快速求出斐波那契数列的第 n 项
  2. 如何快速求解 k*f[n] \, mod\,p=1

对于 1 我们用矩阵快速幂

对于 2 我们用扩展欧几里得算法

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10
using namespace std;
int n,p;
struct matrix
{
	int m[N][N];
}ans,res;
matrix multiply(matrix a,matrix b)
{
	int i,j,k;
	matrix temp;
	for(i=1;i<=2;++i)
	    for(j=1;j<=2;++j)
		temp.m[i][j]=0;
	for(i=1;i<=2;++i)
	    for(j=1;j<=2;++j)
		for(k=1;k<=2;++k)
		    temp.m[i][j]=(temp.m[i][j]+1ll*a.m[i][k]*b.m[k][j])%p;
	return temp;
}
int quickpower(int x)
{
	int i,j;
	res.m[1][1]=1;ans.m[1][1]=1;
	res.m[1][2]=1;ans.m[1][2]=0;
	res.m[2][1]=1;ans.m[2][1]=0;
	res.m[2][2]=0;ans.m[2][2]=1;
	while(x)
	{
		if(x&1)
		  ans=multiply(ans,res);
		res=multiply(res,res);
		x>>=1;
	}
	return ans.m[1][2];
}
int gcd(int a,int b)
{
	int r=a%b;
	while(r!=0)
	{
		a=b;
		b=r;
		r=a%b;
	}
	return b;
}
void exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		x=1;
		y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y-=a/b*x;
}
int main()
{
//	freopen("kfib.in","r",stdin);
//	freopen("kfib.out","w",stdout);
	int x,y,i,r,f;
	scanf("%d%d",&n,&p);
	f=quickpower(n+1);
	r=gcd(f,p);
	if(r!=1)
	  printf("None");
	else
	{
		exgcd(f,p,x,y);
		if(x<0)  x+=p;
		printf("%d",x);
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82219949