cogimyunの小窝

Loading...

CF1152F2 Neko Rules the Catniverse (Large Version) 题解

Ⅰ.Small Version

复制自己 Small Version 的题解。

我们不妨考虑从大到小添加数字,我们不难发现,对于当前已有的序列 \(A\),如果现在添加数字 \(i\),有 \(\forall a_j\in A\ s.t.\ i\le a_j\),则将 \(i\) 直接放在 \(A\) 的尾部必然合法。

接下来考虑将 \(i\) 放在 \(A\) 中间的情况,由于存在限制 \(\forall a_i\in A\)\(i\neq |A|\ s.t\ a_{i+1}\le a_i+m\),则 \(i\) 必须放置在 \(i+1,i+2,...,i+m\) 的前面,又考虑到 \(m\le 4\),我们不妨状压记录下 \(i+1,i+2,...,i+m\) 的选择状态 \(S\),则 \(i\) 插入 \(A\) 中合法的位置数量为 \(\operatorname{popcount(S)}\),其中 \(\operatorname{popcount(S)}\) 表示 \(S\) 在二进制表示下 1 的个数。

于是我们可以设计 \(dp_{i,j,S}\) 表示当前考虑到了第 \(i\) 个数,已经选择了 \(j\) 个数,且 \(i+1,i+2,...,i+m\) 的选择状态为 \(S\) 时的方案数,状态转移方程为:

\[\begin{aligned} &dp_{i,j+1,(\complement_{S}\{i+m\})\cup\{i\}}\leftarrow dp_{i+1,j,S}\times(1+\operatorname{popcount(S)})\hspace{0.5em}(j<k)\\ &dp_{i,j,\complement_{S}\{i+m\}}\leftarrow dp_{i+1,j,S} \end{aligned} \]

时间复杂度为 \(O(nk2^m)\)

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod=1e9+7;
int n,k,m,ans;
int f[100005][15][20];
signed main(){
    cin>>n>>k>>m;
    f[0][0][0]=1;
    for(int i=1;i<=n;i++)for(int j=0;j<=k;j++)for(int l=0;l<(1<<m);l++){
        if(j!=k)f[i][j+1][((l<<1)|1)&((1<<m)-1)]=(f[i][j+1][((l<<1)|1)&((1<<m)-1)]+f[i-1][j][l]*(1+__builtin_popcount(l)))%mod;
        f[i][j][(l<<1)&((1<<m)-1)]=(f[i][j][(l<<1)&((1<<m)-1)]+f[i-1][j][l])%mod;
    }
    for(int i=0;i<(1<<m);i++)ans=(ans+f[n][k][i])%mod;
    cout<<ans;
    return 0;
}

Ⅱ.Hard Version

考虑继续优化上面的算法,发现转移和 \(i\) 无关,于是我们可以考虑使用矩阵快速幂优化这个过程,将 Small Version 中的转移方程式转化为矩阵的形式确定 \(dp_{0,0,0}\) 的系数即可,其中 \(dp_{0,0,0}\) 按照题意应该为 1。

时间复杂度为 \(O(k^38^m\log n)\)

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int n,m,k,ans;
struct matrix{
    int a[500][500];
}a;
matrix operator*(matrix x,matrix y){
    matrix z;
    for(int i=1;i<=(k+1)*(1<<m);i++)for(int j=1;j<=(k+1)*(1<<m);j++)z.a[i][j]=0;
    for(int i=1;i<=(k+1)*(1<<m);i++)for(int j=1;j<=(k+1)*(1<<m);j++)for(int l=1;l<=(k+1)*(1<<m);l++)z.a[i][j]=(z.a[i][j]+x.a[i][l]*y.a[l][j]%mod)%mod;
    return z;
}
matrix power(int x){
    matrix res=a;
    matrix ans=a;
    x--;
    while(x){
        if(x&1)ans=ans*res;
        res=res*res;
        x>>=1;
    }
    return ans;
}
void init(){
    for(int i=0;i<=k;i++)for(int j=0;j<(1<<m);j++){
        if(i!=k)a.a[i*(1<<m)+j+1][(i+1)*(1<<m)+(((j<<1)|1)&((1<<m)-1))+1]+=1+__builtin_popcount(j);
        a.a[i*(1<<m)+j+1][i*(1<<m)+((j<<1)&((1<<m)-1))+1]++;
    }
}
signed main(){
    cin>>n>>k>>m;
    init();
    matrix b=power(n);
    for(int i=0;i<(1<<m);i++)ans=(ans+b.a[1][k*(1<<m)+i+1])%mod;
    cout<<ans;
    return 0;
}
posted @ 2026-01-08 07:30  cogimyun  阅读(1)  评论(0)    收藏  举报