【二次剩余】BZOJ5118 Fib数列2

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89507890

【题目】
lydsy
f i b ( 2 n ) , n 1 0 15 fib(2^n),n\leq 10^{15} ,答案对 1125899839733759 1125899839733759 取模

【解题思路】
打表可以发现模数是个素数,个位数又是九,所以根号五有二次剩余。
于是就是二次剩余板子,用斐波那契的通项来求就行了。
注意扩域的复数乘法,虚部实际上是 x 2 a \sqrt {x^2-a}

【参考代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef long double db;
const ll mod=1125899839733759ll,inv2=(mod+1)>>1;

namespace Cipolla
{
	ll w;
	ll mul(ll x,ll y,ll p=mod){return ((x*y-(ll)((db)x/p*y+0.5)*p)%p+p)%p;}
	/*ll mul(ll x,ll y,ll p=mod)
	{
		ll res=0;
		for(;y;y>>=1,x=(x+x)%p) if(y&1) res=(res+x)%p;
		return res;
	}*/
	struct cd
	{
		ll x,y;
		cd(ll _x=0,ll _y=0):x(_x),y(_y){}
		cd operator *(const cd&A)const{return cd((mul(x,A.x)+mul(mul(y,A.y),w))%mod,(mul(x,A.y)+mul(y,A.x))%mod);}
	};
	ll ipow(cd x,ll y)
	{
		cd res=cd(1,0);
		for(;y;y>>=1,x=x*x)if(y&1)res=res*x;
		return res.x;
	}
	ll qpow(ll x,ll y,ll p=mod)
	{
		ll res=1;
		for(;y;y>>=1,x=mul(x,x,p))if(y&1)res=mul(res,x,p);
		return res;
	}
	ll calc(ll x,ll p=mod)
	{
		if(!x) return 0;
		ll t=qpow(x,(p-1)>>1,p);
		if(t==mod-1) return -1;
		for(;;)
		{
			t=mul(rand()%p,rand()%p,p);w=(mul(t,t)-x+p)%p;
			if(qpow(w,(p-1)>>1,p)==p-1) return ipow(cd(t,1),(p+1)>>1);
		}
	}
}
using namespace Cipolla;

int main()
{
#ifdef Durant_Lee
	freopen("BZOJ5118.in","r",stdin);
	freopen("BZOJ5118.out","w",stdout);
#endif
	srand(2333);
	ll sq5,A,B,iv,n,ans,T;
	sq5=calc(5);A=mul(sq5+1,inv2);B=mul(sq5-1,inv2);iv=qpow(sq5,mod-2);
	//cerr<<sq5<<endl;
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld",&n);n=qpow(2,n,mod-1);
		ans=mul(iv,(qpow(A,n)-qpow(B,n)+mod)%mod);
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/89507890