BZOJ 3328: PYXFIB 解题报告

BZOJ 3328: PYXFIB

题意

给定(n,p,k(1le nle 10^{18},1le kle 20000,1le ple 10^9,p is prime,k|(p-1))),求

[sum_{i=0}^{lfloorfrac{n}{k} floor}inom{n}{ik}F_{ik} ]

其中(F_{i})代表斐波那契数列的第(i)项。


首先分析一波题目条件,有个很奇怪的条件(k|varphi(p))

如果对NTT或者单位根有所了解,我们可以猜到这个条件可以取出单位根来。

[w_k=g^{frac{p-1}{k}} ]

然而如果没发现,推一波式子之后也可以发现需要使用单位根。

不过可以先考虑如何处理fib,一个简单的想法是构造矩阵乘法,比如

[A=egin{bmatrix}1&1\1& 0end{bmatrix} ]

可以得到

[A^i=egin{bmatrix}F_i&F_{i-1}\dots&dotsend{bmatrix} ]

然后我们直接把式子转换成求矩阵

[egin{aligned} &sum_{i=0}^{lfloorfrac{n}{k} floor}inom{n}{ik}A^{ik}\ =&sum_{i=0}^ninom{n}{i}A^i[k|i]\ =&sum_{i=0}^ninom{n}{i}A^ifrac{1}{k}sum_{j=0}^{k-1}w_k^{ij}\ =&frac{1}{k}sum_{j=0}^{k-1}sum_{i=0}^ninom{n}{i}A^i(w_k^j)^i\ =&frac{1}{k}sum_{j=0}^{k-1}(w_k^jA+I)^n end{aligned} ]

复杂度(O(Tklog n))


Code:

#include <cstdio>
#include <cctype>
#define ll long long
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
//#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
#define gc() getchar()
template <class T>
void read(T &x)
{
	x=0;char c=gc();
	while(!isdigit(c)) c=gc();
	while(isdigit(c)) x=x*10+c-'0',c=gc();
}
ll n;
int k,p;
inline int add(int a,int b){return a+b>=p?a+b-p:a+b;}
#define mul(a,b) (1ll*(a)*(b)%p)
inline int qp(int d,int k)
{
	int f=1;
	while(k)
	{
		if(k&1) f=mul(f,d);
		d=mul(d,d);
		k>>=1;
	}
	return f;
}
struct Matrix
{
	int a,b,c,d;
	Matrix friend operator *(Matrix a,Matrix b)
	{
		Matrix c;
		c.a=add(mul(a.a,b.a),mul(a.b,b.c));
		c.b=add(mul(a.a,b.b),mul(a.b,b.d));
		c.c=add(mul(a.c,b.a),mul(a.d,b.c));
		c.d=add(mul(a.c,b.b),mul(a.d,b.d));
		return c;
	}
}A;
inline Matrix mqp(Matrix d,ll k)
{
	Matrix f=d;--k;
	while(k)
	{
		if(k&1) f=f*d;
		d=d*d;
		k>>=1;
	}
	return f;
}
int getg(int p)
{
	int s[30]={},phi=p-1;
	for(int i=2;i*i<=phi;i++)
	{
		if(phi%i==0)
		{
			s[++s[0]]=i;
			while(phi%i==0) phi/=i;
		}
	}
	if(phi!=1) s[++s[0]]=phi;
	for(int i=2;;i++)
	{
		int flag=1;
		for(int j=1;j<=s[0];j++)
			if(qp(i,(p-1)/s[j])==1)
			{
				flag=0;
				break;
			}
		if(flag) return i;
	}
}
int main()
{
	int T;read(T);
	while(T--)
	{
		read(n),read(k),read(p);
		int w=qp(getg(p),(p-1)/k),ans=0;
		for(int j=0;j<k;j++)
		{
			A.a=A.b=A.c=qp(w,j),A.d=1;
			A.a=add(A.a,1);
			A=mqp(A,n);
			ans=add(ans,A.a);
		}
		printf("%lld
",mul(ans,qp(k,p-2)));	
	}
	return 0;
}

2019.5.8

原文地址:https://www.cnblogs.com/butterflydew/p/10830216.html