[atAGC055F]Creative Splitting

考虑判定序列$\{b_{i}\}$是否"amazing"——

维护$n$个序列的剩余长度,从后往前枚举$b_{i}$,问题转换为以下模型:

对于长为$n$的序列$\{c_{j}\}$(初始均为$k$),每次选择$c_{j}\ge b_{i}$减1,要求存在一种合法方案

事实上,可以贪心选择最小的$c_{j}$减1,证明如下:

引理:对于存在合法方案的$\{c_{j}\}$,贪心操作一次后仍存在

假设贪心操作$x$而合法方案操作$y$,若$c_{x}=c_{y}$即得证,进而有$c_{x}<c_{y}$

不妨强制该方案在$c_{x}=c_{y}$时不操作$y$(操作$x$等价),即恒有$c_{x}\le c_{y}$

构造:操作$x$后模仿该方案操作,仅将下一次操作$x$改为操作$y$

关于构造的合法性,分为三部分:

1.下一次操作$x$之前,注意到仅有$c_{x}$较小,显然成立

2.下一次操作$x$时,由于$c_{x}\le c_{y}$,改为操作$c_{y}$也合法

3.下一次操作$x$之后,两者$\{c_{j}\}$均相同,显然成立

综上,根据引理归纳即得证

记$c'_{i}=\sum_{j=1}^{n}[c_{j}<i]$,则操作时对应的影响即将$c'_{b_{i}}$加1并重新排序(可以自行分析)

在此基础上,结合$b_{pos}=val$的限制,问题又转换为以下模型:

对于长为$k$的序列$\{c'_{i}\}$(初始均为$0$),每次将$c'_{b_{i}}\ne n$加1并重新排序,求$b_{pos}=val$的方案数

在$\{b_{i}\}$无限制时,重新排序并没有意义,进而方案数可以用组合数得到

对于$b_{pos}=val$的限制,考虑枚举在$i=pos$处排序后的$\{c'_{i}\}$,则答案即
$$
\sum_{\begin{array}{}0\le c'_{1}\le c'_{2}\le ...\le c'_{k}\le n\\\sum_{i=1}^{k}c'_{i}=nk-pos\end{array}}P(\{c'_{i}\}){nk-pos\choose c'_{1},c'_{2},...,c'_{k}}{pos-1\choose n-c'_{1},n-c'_{2},...,n-c'_{val}-1,...,n-c'_{k}}
$$
(其中$P(\{c'_{i}\})$表示$\{c'_{i}\}$任意排列所能得到的不同序列数)

仅需对每一个$val$进行一次dp,单次dp复杂度为$o(n^{2}k^{3})$,总复杂度为$o(n^{2}k^{4})$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 30
 4 #define M 500
 5 #define ll long long
 6 int n,m,mod,fac[M],inv[N],g[M],f[N][N][M],ans[M][N];
 7 int main(){
 8     scanf("%d%d%d",&n,&m,&mod);
 9     fac[0]=inv[0]=inv[1]=1;
10     for(int i=1;i<M;i++)fac[i]=(ll)fac[i-1]*i%mod;
11     for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
12     for(int i=1;i<N;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
13     for(int val=1;val<=m;val++){
14         memset(f,0,sizeof(f));
15         for(int i=1;i<=m;i++){
16             memset(g,0,sizeof(g));
17             if (i==1)g[0]=1;
18             for(int j=0;j<=n;j++){
19                 for(int k=0;k<=n*m;k++){
20                     if (!g[k])continue;
21                     int k0=k,s=g[k];
22                     for(int ii=i;ii<=m;ii++){
23                         if ((ii==val)&&(j==n))break;
24                         k0+=j,s=(ll)s*inv[j]%mod*inv[n-j-(ii==val)]%mod;
25                         f[ii][j][k0]=(f[ii][j][k0]+(ll)s*inv[ii-i+1])%mod;
26                     }
27                 }
28                 for(int k=0;k<=n*m;k++)g[k]=(g[k]+f[i-1][j][k])%mod;
29             }
30         }
31         for(int pos=1;pos<=n*m;pos++){
32             for(int i=0;i<=n;i++)ans[pos][val]=(ans[pos][val]+f[m][i][n*m-pos])%mod;
33             ans[pos][val]=(ll)ans[pos][val]*fac[m]%mod*fac[n*m-pos]%mod*fac[pos-1]%mod;
34         }
35     }
36     for(int pos=1;pos<=n*m;pos++){
37         for(int val=1;val<=m;val++)printf("%d ",ans[pos][val]);
38         printf("\n");
39     }
40     return 0;
41 }
View Code

 

posted @ 2022-04-21 19:34  PYWBKTDA  阅读(155)  评论(0编辑  收藏  举报