BZOJ3328: PYXFIB

42 篇文章 0 订阅
11 篇文章 0 订阅

我们要求这个东西 ni=0CinFi[i mod k=0] ∑ i = 0 n C n i F i [ i   m o d   k = 0 ]
先不考虑 k|i k | i 这个条件,即只计算 ni=0CinFi ∑ i = 0 n C n i F i
设出Fib数列的转移矩阵 A A ,那么Fi就是 Ai A i 的左上角
再考虑二项式定理 (a+b)n=ni=0aibni ( a + b ) n = ∑ i = 0 n a i b n − i ,在矩阵运算中同样适用(满足分配律,结合律)
那么我们可以得到

i=0nCinFi=i=0n(ni)AiIni=(A+I)n ∑ i = 0 n C n i F i = ∑ i = 0 n ( i n ) A i I n − i = ( A + I ) n
I I 是单位矩阵


接下来考虑构造一个[i mod k=0]的函数
注意到 k1 Mod p k ≡ 1   M o d   p ,即 k|p1,phi(p)=p1 k | p − 1 , p h i ( p ) = p − 1
因此我们求出 p p 的原根g,令 w=gp1k w = g p − 1 k ,那么 wi1modp w i ≡ 1 mod p 当且仅当 k|i k | i
并且有这么个柿子 k1j=0wij=k[i mod k=0] ∑ j = 0 k − 1 w i j = k [ i   m o d   k = 0 ]
证明:当 k|i k | i 时, wi=1 w i = 1 ,显然和为 k k ,否则是个以1为首项,wi为公比的等比数列, 1wik1wi 1 − w i k 1 − w i ,分子为0,和为0
那么我们就构造出了我们想要的函数:
1kk1j=0wij=[i mod k=0] 1 k ∑ j = 0 k − 1 w i j = [ i   m o d   k = 0 ]


那么最后的答案就是
ni=0(ni)Fi[i mod k=0] ∑ i = 0 n ( i n ) F i [ i   m o d   k = 0 ]
= ni=0(ni)Ai1kk1j=0wij ∑ i = 0 n ( i n ) A i 1 k ∑ j = 0 k − 1 w i j
= 1kk1j=0ni=0(ni)AiIniwji 1 k ∑ j = 0 k − 1 ∑ i = 0 n ( i n ) A i I n − i w j i
= 1kk1j=0wnjni=0(ni)Ai(Iwj)ni 1 k ∑ j = 0 k − 1 w n j ∑ i = 0 n ( i n ) A i ( I w − j ) n − i
= 1kk1j=0wnj(A+Iwj)n 1 k ∑ j = 0 k − 1 w n j ( A + I w − j ) n
注意这里 wij w i j 只能和 I I 结合到一起不能Aw这样子,因为一般矩阵 A A 是不满足交换律的,但是单位矩阵I特殊,他满足交换律,所以可以弄成 Iwj I w − j 这样子

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 110;

int pwmod(int x,ll k,int mod)
{
    int re=1;
    for(;k;k>>=1,x=(ll)x*x%mod) if(k&1ll)
        re=(ll)re*x%mod;
    return re;
}
int Inv(int x,int mod){return pwmod(x,mod-2,mod);}
int t[maxn],tp;
int get_g(int P)
{
    int p=P-1;
    tp=0;
    for(int i=2;i*i<=p;i++) if(p%i==0)
    {
        t[++tp]=i; while(p%i==0) p/=i;
    }
    if(p>1) t[++tp]=p;
    p=P-1;
    for(int i=2;;i++)
    {
        int ok=1;
        for(int j=1;j<=tp;j++)
            if(pwmod(i,p/t[j],P)==1) { ok=0;break; }
        if(ok) return i;
    }
}

ll n;
int K,mod,ans;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}
struct mat
{
    int a[2][2];
    mat(){memset(a,0,sizeof a);}
    friend inline mat operator *(const mat &x,const mat &y)
    {
        mat re;
        for(int i=0;i<2;i++) for(int k=0;k<2;k++)
            for(int j=0;j<2;j++) add(re.a[i][j],(ll)x.a[i][k]*y.a[k][j]%mod);
        return re;
    }
    friend inline mat operator ^(const mat &x,const int &y)
    {
        mat re;
        for(int i=0;i<2;i++) for(int j=0;j<2;j++) re.a[i][j]=(ll)x.a[i][j]*y%mod;
        return re;
    }
    friend inline mat operator +(const mat &x,const mat &y)
    {
        mat re;
        for(int i=0;i<2;i++) for(int j=0;j<2;j++) re.a[i][j]=(x.a[i][j]+y.a[i][j])%mod;
        return re;
    }
}A,one,W;
mat pw(mat x,ll k)
{
    mat re=one;
    for(;k;k>>=1,x=x*x) if(k&1ll)
        re=re*x;
    return re;
}

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    A.a[0][0]=A.a[0][1]=A.a[1][0]=1;
    one.a[0][0]=one.a[1][1]=1;

    int T;scanf("%d",&T);
    while(T--)
    {
        ans=0;

        scanf("%lld%d%d",&n,&K,&mod);
        int g=get_g(mod);
        int w=pwmod(g,(mod-1)/K,mod),inv=Inv(w,mod),wj=1;
        W=one;
        for(int j=0;j<K;j++)
        {
            mat temp=A+W,tn=pw(temp,n);
            add(ans,(ll)pwmod(wj,n,mod)*tn.a[0][0]%mod);
            if(ans<0) ans+=mod;
            W=W^inv; wj=(ll)wj*w%mod;
        }

        printf("%lld\n",(ll)ans*Inv(K,mod)%mod);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值