zoukankan      html  css  js  c++  java
  • 【BZOJ3328】PYXFIB 数论+矩阵乘法

    【BZOJ3328】PYXFIB

    Description

    Input

    第一行一个正整数,表示数据组数据 ,接下来T行
    每行三个正整数N,K,P

    Output

    T行,每行输出一个整数,表示结果

    Sample Input

    1
    1 2 3

    Sample Output

    1

    HINT

    题解:首先看到斐波那契数列我们肯定要想到矩阵乘法,但是给出的形式并不能直接求,我们试图将其转化为矩乘的形式。

    如果不考虑k的话,我们可以设A表示斐波那契数列的转移矩阵,然后套用二项式定理(这显然对矩阵运算成立),得到$ans=(I+A)^n$。

    如果考虑k的限制呢?所求的式子变成$sumlimits_{i=0}^n[kmid i]C_n^iF_i$。而题中保证p是质数且p%k=1,即(p-1)%k=0,p-1的出现暗示着我们可能要用到原根。

    接下来就是最神的一步:设g是p的原根,$g^{ifrac {p-1} k}=1$当且仅当$kmid i$,所以令$w=g^{frac {p-1} k}$,我们构造:$sumlimits_{j=0}^{k-1}w^{ij}$,这个式子当$kmid i$时=k,而当$k mid i$时,由等比数列求和可知该式=0。所以答案就可以表示成$sumlimits_{i=0}^{n}frac 1 k sumlimits_{j=0}^{k-1}w^{ij}C_n^iF_i$。

    下一步也挺神的(其实应该是个我不知道的套路),我们希望对这个式子强行套用二项式定理,但是这个式子本身并不满足二项式定理的形式,所以我们先枚举j,得到$frac 1 k sumlimits_{j=0}^{k-1}sumlimits_{i=0}^nw^{ij}C_n^iF_i$。如果想套用二项式定理,我们需要式子中有一个n-i,于是我们强行把$w^{ij}$变成$w^{nj-(n-i)j}$,然后将$w^{nj}$提出来即可,最后的形式如下:

    $frac 1 k sumlimits_{j=0}^{k-1}w^{nj}(w^{-j}I+A)^n$。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    ll n,k,P,ans,g,w;
    int m;
    ll pri[20];
    struct M
    {
    	ll v[2][2];
    	M () {memset(v,0,sizeof(v));}
    	ll * operator [] (const int &a) {return v[a];}
    	M operator * (const M &a) const
    	{
    		M b;
    		int i,j,k;
    		for(i=0;i<2;i++)	for(j=0;j<2;j++)	for(k=0;k<2;k++)	b.v[i][j]=(b.v[i][j]+v[i][k]*a.v[k][j])%P;
    		return b;
    	}
    }S,T;
    inline ll pm(ll x,ll y)
    {
    	ll z=1;
    	while(y)
    	{
    		if(y&1)	z=z*x%P;
    		x=x*x%P,y>>=1;
    	}
    	return z;
    }
    inline void pm(ll y)
    {
    	while(y)
    	{
    		if(y&1)	S=S*T;
    		T=T*T,y>>=1;
    	}
    }
    inline void work()
    {
    	ans=0,m=0;
    	scanf("%lld%lld%lld",&n,&k,&P);
    	int i;
    	ll t=P-1;
    	for(i=2;i*i<=t;i++)	if(t%i==0)
    	{
    		pri[++m]=i;
    		while(t%i==0)	t/=i;
    	}
    	if(t>1)	pri[++m]=t;
    	for(g=2;;g++)
    	{
    		for(i=1;i<=m;i++)	if(pm(g,(P-1)/pri[i])==1)	break;
    		if(i>m)	break;
    	}
    	w=pm(g,(P-1)/k);
    	for(i=0;i<k;i++)
    	{
    		S[0][0]=1,S[1][1]=S[0][1]=S[1][0]=0;
    		t=pm(w,P-1-i);
    		T[0][0]=T[1][0]=T[0][1]=1,T[0][0]+=t,T[1][1]=t;
    		pm(n);
    		t=S[0][0];
    		ans=(ans+t*pm(w,n%(P-1)*i))%P;
    	}
    	printf("%lld
    ",ans*pm(k,P-2)%P);
    }
    int main()
    {
    	int cas;
    	scanf("%d",&cas);
    	while(cas--)	work();
    	return 0;
    }//1 100000000000000000 15232 998244353
  • 相关阅读:
    动态传参
    函数的介绍
    文件的操作
    send email with formatted table
    minimize and close window with customed winform
    python algorithm
    something important about docker
    book list
    which language is suitable for what to do
    Find Duplicate Items in list fast
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8289889.html
Copyright © 2011-2022 走看看