[BZOJ3328]PYXFIB

PYXFIB

题解

一看就是一道的数论题。谁都知道

至于斐波拉契的做法应该都知道,用一个A=\begin{pmatrix} 1 & 1\\ 1 & 0 \end{pmatrix}的矩阵就可以处理了。

关键是如何解决前面那个组合数呢?

通过这个式子\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}C_{n}^{ik}\cdot A^{ik},很容易想到二项式展开定理(a+ b)^{n}= \sum_{i=0}^{n} \binom{n}{i}a^{i}

针对矩阵肯定也是成立的,\left (A+ I \right )= \sum_{i=0}^{n}\binom{n}{i}a^{i},(I为单位矩阵)。

不过我们还需判断[k|i],这样就与原式等价了。

我们现在的目的是构造一个数组a使得满足a_{i}=[k|i]

g为p的原根,w为p的单位根即w= g^{\frac{p-1}{k}}。那么当且仅当w^{i}=1在模p的意义下。所以\sum_{j=0}^{k-1}w^{ij}只有在k|i时为k,其他时候都为0。

于是原式等价于\frac{1}{k}\sum_{i=0}^{n}\binom{n}{i}A^{i}\sum_{j=0}^{k-1}w^{ij}

我们设F\left ( x \right )= x^{-n}(xI+A)^{n}k= \sum_{i=0}^{n}\binom{n}{i}x^{-i}A^{i}

于是\frac{1}{k}(F\left(w^{-0} \right )+ F\left(w^{-1} \right )+... +F\left(w^{k-1} \right ))= \frac{1}{k}\sum_{i=0}^{n}\binom{n}{i}A^{i}\sum_{j=0}^{k-1}w^{ij}

这就很容易用矩阵快速幂求出了。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; 
#define int LL
#define gc() getchar()
template<typename _T>
inline void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
int cnt,n,k,p,y[1000005];
int pow(int a,int s){
	int t=1;a%=p;
	while(s){
		if(s&1)t=a*t%p;
		a=a*a%p;s>>=1;
	}
	return t;
}
struct matrix{
    int n,m,c[20][20];
    matrix(){n=m=0;memset(c,0,sizeof(c));}
    matrix operator * (const matrix& a){
        matrix r;r.n=n;r.m=a.m;
        for(int i=1;i<=r.n;i++)
            for(int j=1;j<=r.m;j++)
                for(int k=1;k<=m;k++)
                    (r.c[i][j]+=(c[i][k]*a.c[k][j]%p))%=p;
        return r;
    }
    matrix operator + (const matrix& a){
    	matrix r;r.n=n;r.m=m;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			r.c[i][j]=(a.c[i][j]+c[i][j])%p;
    	return r;
	}
}A;
matrix qkpow(matrix a,LL s){
	matrix res;res.n=res.m=a.n;
	for(int i=1;i<=res.m;i++) res.c[i][i]=1;
	while(s){
		if(s&1)res=res*a;
		a=a*a;s/=2;
	}
	return res;
}
int calc(int x){
	matrix ans;ans.n=ans.m=2;
	ans.c[1][1]=ans.c[2][2]=x;ans.c[1][2]=ans.c[2][1]=0;
	ans=ans+A;ans=qkpow(ans,n);
	int nix=pow(pow(x,n),p-2);
	for(int i=1;i<=ans.n;i++)
		for(int j=1;j<=ans.m;j++)
			ans.c[i][j]=ans.c[i][j]*nix%p;
	return ans.c[1][1];
}
bool judge(int x){
	for(int i=1;i<=cnt;i++)
		if(pow(x,y[i])%p==1)
			return false;
	return true;
}
void get_yinshu(int x){
	for(int i=2;i<=sqrt(x);i++){
		if(x%i)continue;
		y[++cnt]=i;
		if(x/i>i)y[++cnt]=x/i;
	}
}
int get_w(){
	get_yinshu(p-1);int g;
	for(g=2;g;g++)if(judge(g))break;
	return pow(g,(p-1)/k);
}
signed main(){
	int t;read(t);
	while(t--){
		cnt=0;A.n=A.m=2;
		A.c[1][1]=A.c[1][2]=A.c[2][1]=1;A.c[2][2]=0;
		read(n);read(k);read(p);
		int w=get_w(),ans=0,ni=pow(pow(w,k-1),p-2);
		ans=(ans+calc(ni))%p;
		for(int i=k-2;i>=0;i--)
			ni=ni*w%p,ans=(ans+calc(ni))%p;
		printf("%lld\n",ans*pow(k,p-2)%p);
	}
    return 0;
}

谢谢!!!

发布了117 篇原创文章 · 获赞 154 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/104084760