CF1152F Neko Rules the Catniverse

Link
简化题意:
给定正整数(n,k,m),求有多少个满足下列条件的长度为(k)的序列({a})
(1.forall1le i<jle k,a_i e a_j)
(2.forall iin[1,k],a_iin[1,n])
(3.forall iin(1,k],a_ile a_{i-1}+m)
考虑从小往大考虑每个数,假如我们的数是(x),那么我们现在可以选择放或不放。
如果放,那么我们可以放在序列末尾,或者是某个([x-m,x))范围内的数的前面。
([x-m,x))的数是否在序列中状压即可转移。
(f_{i,j,k})表示当前的数是(i),序列中已经放了(j)个数,([i-m,i))的数的状态为(k)时的答案。
(S=2^m-1),转移如下:
不放:(f_{i,j,k} ightarrow f_{i+1,j,k<<1&S})
放:((operatorname{bit}k+1)f_{i,j,k} ightarrow f_{i+1,j+1,k<<1&S|1})
直接做是(O(nk2^m))的。注意到后面转移与(i)无关,所以把后面两维压成一维,然后矩阵快速幂优化即可,时间复杂度为(O((k2^m)^3log n))

#include<cstdio>
#include<cstring>
const int P=1000000007;
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int tot,id[13][16],cnt[16];
struct matrix{int a[220][220];matrix(){memset(a,0,sizeof a);}int*operator[](int x){return a[x];}}E,I;
matrix operator*(matrix a,matrix b)
{
    matrix c;
    for(int i=1;i<=tot;++i) for(int j=1;j<=tot;++j) for(int k=1;k<=tot;++k) c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%P;
    return c;
}
int main()
{
    int n=read(),k=read(),m=read(),S=(1<<m)-1,ans=0;I[1][1]=1;
    for(int i=1;i<=S;++i) cnt[i]=cnt[i>>1]+(i&1);
    for(int i=0;i<=k;++i) for(int s=0;s<=S;++s) id[i][s]=++tot;
    for(int i=0;i<=k;++i)
        for(int s=0,t;s<=S;++s)
        {
            inc(E[id[i][s]][id[i][t=s<<1&S]],1);
            if(i^k) inc(E[id[i][s]][id[i+1][t|1]],cnt[s]+1);
        }
    for(;n;n>>=1,E=E*E) if(n&1) I=I*E;
    for(int i=0;i<1<<m;++i) inc(ans,I[1][id[k][i]]);
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12441568.html