交错序列

交错序列

长度为n的01序列的的一种方案中,保证1不能相邻,记0出现x次,1出现y次,定义其特征值为\(x^ay^b\),参数a,b已事先给定,求所有方案的特征值\(mod\) m,m为给定质数,1≤n≤10000000 0≤a,b≤45 m<100000000。

对于一种方案分析

\[\because x+y==n\therefore x^ay^b=(n-y)^ay^b= \]

\[\sum_{i=0}^aC_a^in^i(-y)^{a-i}y^b=\sum_{i=0}^a(-1)^{a-i}C_a^in^iy^{a+b-i} \]

注意到a,b很小,而前面式子为定值,于是只要求出每种方案的1的个数的次方即可累加即可,所以设\(f[i][j][0/1]\)表示填到第i个数,这个数填0/1,的方案数的所有1的个数的j次方之和,不难有

\[f[i][j][0]=f[i-1][j][0]+f[i-1][j][1] \]

\[f[i][j][1]=\sum_{k=0}^jf[i-1][k][0]C_J^k \]

注意到数据范围很大,必然\(O((a+b)n)\)会超时,考虑到第二维第三维很少,方程较为简单,于是矩阵快速幂优化,压维存下第二维第三维即可,此外考虑到矩阵维数很少,模数较小,于是可以矩阵乘法实现时,加完一个for询问再取模。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define ll long long
using namespace std;
ll n,a,b,lsy,mid,li,
    c[91][91],pown[91],
    qf[91],ans;
struct matrix{
    ll num[183][183];
    il void clear(){memset(num,0,sizeof(num));}
    il void unit(){
        clear();for(ri int i(0);i<=li;++i)
                    num[i][i]|=true;
    }
    il void print(){
        for(ri int i(0),j;i<=li;++i,putchar('\n'))
            for(j=0;j<=li;++j)printf("%d ",num[i][j]);
        putchar('\n');
    }
    il matrix operator*(matrix x){
        matrix y;y.clear();
        for(ri int i(0),j,k;i<=li;++i)
            for(j=0;j<=li;y.num[i][j]%=lsy,++j)
                for(k=0;k<=li;++k)
                    y.num[i][j]+=num[i][k]*x.num[k][j];
        return y;
    }template<class free>
    il matrix operator^(free y){
        matrix ans,x(*this);ans.unit();
        while(y){
            if(y&1)ans=ans*x;
            x=x*x,y>>=1;
        }return ans;
    }
}state,tran;
int main(){
    int i,j,k;
    scanf("%lld%lld%lld%lld",&n,&a,&b,&lsy);
    mid=a+b,li=(mid<<1)+1;
    for(i=0;i<=mid;++i){
        c[i][0]=1;
        for(j=1;j<=i;++j)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%lsy;
    }
    for(i=0;i<=mid;++i)
        tran.num[i][i]=tran.num[i+mid+1][i]=1;
    for(j=mid+1;j<=li;++j)
        for(k=0;k<=j-mid-1;++k)
            tran.num[k][j]=c[j-mid-1][k];
    for(i=mid+1;i<=li;++i)state.num[0][i]=1;
    state.num[0][0]=1,state=state*(tran^n-1);
    for(i=0;i<=mid;++i)state.num[0][i]+=state.num[0][i+mid+1];
    for(i=pown[0]=qf[0]=1;i<=mid;++i)pown[i]=pown[i-1]*n%lsy,qf[i]=qf[i-1]*(-1);
    for(j=0;j<=a;++j)ans+=(pown[j]*c[a][j]%lsy*qf[a-j]+lsy)%lsy*state.num[0][a+b-j]%lsy,
                         ans%=lsy;
    printf("%lld",ans);
    return 0;
}

posted @ 2019-04-30 11:58  a1b3c7d9  阅读(271)  评论(0编辑  收藏  举报