【BZOJ4002】[JLOI2015]有意义的字符串(数论,矩阵快速幂)

【BZOJ4002】[JLOI2015]有意义的字符串(数论,矩阵快速幂)

题面

BZOJ
洛谷

题解

发现我这种题总是做不动。。。
\(A=\frac{b+\sqrt d}{2},B=\frac{b-\sqrt d}{2}\)
发现\(A+B=b,AB=\frac{b^2-d}{4}\)
要求的东西是\(A^n\),我们变成\(A^n+B^n-B^n\)
分开考虑,发现\(A^n+B^n=(A^{n-1}+B^{n-1})(A+B)-(A^{n-2}+B^{n-2})AB\),这样子前面一半可以矩乘直接求。
后面一般根据数据范围,发现要么是\(0\),要么是\(-1\)
那么直接特判一下就可以求了。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
const ll MOD=7528443412579576937ll;
ll Multi(ll a,ll b){ll s=a*b-(ll)((long double)a/MOD*b+0.5)*MOD;return s<0?s+MOD:s;}
ll Plus(ll a,ll b){unsigned ll c=(0ull+a+b)%MOD;return c;}
ll b,d,n,ans;
struct Matrix
{
	ll s[2][2];
	void clear(){s[0][0]=s[0][1]=s[1][0]=s[1][1]=0;}
	void init(){s[0][0]=s[1][1]=1;s[1][0]=s[0][1]=0;}
	ll*operator[](int x){return s[x];}
}T;
Matrix operator*(Matrix a,Matrix b)
{
	Matrix c;c.clear();
	for(int i=0;i<2;++i)
		for(int j=0;j<2;++j)
			for(int k=0;k<2;++k)
				c[i][j]=Plus(c[i][j],Multi(a[i][k],b[k][j]));
	return c;
}
int main()
{
	scanf("%lld%lld%lld",&b,&d,&n);
	if(!n){puts("1");return 0;}
	T[0][0]=0;T[0][1]=(d-b*b)/4;
	T[1][0]=1;T[1][1]=b;
	if(!(n&1)&&b*b<d)ans=MOD-1;
	Matrix s;s.init();n-=1;
	while(n){if(n&1)s=s*T;T=T*T;n>>=1;}
	ans=Plus(ans,Plus(Multi(2,s[0][1]),Multi(b,s[1][1])));
	printf("%lld\n",ans);
	return 0;
}
		
posted @ 2019-04-24 22:30  小蒟蒻yyb  阅读(335)  评论(0编辑  收藏  举报