cogimyunの小窝

Loading...

CF1152F1 Neko Rules the Catniverse (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;
}
posted @ 2026-01-08 07:29  cogimyun  阅读(1)  评论(0)    收藏  举报