zoukankan      html  css  js  c++  java
  • [atAGC055F]Creative Splitting

    考虑判定序列$\{b_{i}\}$是否"amazing",从后往前拆分,即等价于如下问题:

    初始$c_{i}$均为$k$(长度为$n$),从大到小枚举$i$并选择$c_{j}\ge b_{i}$减1,判定最终能否使$c_{i}$均为0

    关于这个问题,可以贪心选择最小的$c_{j}$操作,证明如下:

    注意到$c_{i}$是无序的,即$c_{x}=c_{y}$时操作$x$和$y$是等价的

    引理:对于任意有解的$c_{i}$,贪心操作一次后仍有解

    假设贪心操作$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}$也合法,进而与1.相同

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

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

    同时,上述贪心也等价于不断选择最小的$j$操作(归纳$c_{1}\le c_{2}\le ...\le c_{n}$即可证明)

    显然操作方式唯一,不妨枚举操作方式(即每一次操作的$j$)并统计amazing的序列数:

    操作$c_{j}$时对应的$b_{i}$范围为$(c_{j-1},c_{j}]$,即有$c_{j}-c_{j-1}$种方式将$c_{j}$​减1

    换言之,将每一次(操作前)的$c_{j}-c_{j-1}$相乘后即为序列数(特别的,约定$c_{0}=0$)

    进一步的,考虑这样一个构造:

    有$n+1$个格子(编号为$[0,n]$),初始$0$上有$k$个球(编号为$[1,k]$),每次操作将一个球向右移动一格,执行此操作$nk$次使所有球均在$n$上的所有方案

    记$c_{i}$为$[0,i)$这些格子上球的数量,初始$c_{i}$均为$k$,将$i$上的球向右移动即将$c_{i}$减1,且有$c_{i}-c_{i-1}$种方式,最终使得$c_{i}$均为0的所有方案

    不难发现,这与amazing的序列计数是相同的,不妨考虑这个构造的问题:

    不考虑$b_{pos}=val$的限制,显然这个问题的答案(也即amazing的序列总数)为${nk\choose n,n,...,n}$(共$k$个$n$)

    关于$b_{pos}=val$的限制,对应于此问题中,即第$nk-pos+1$次操作必须选择第$val$个球操作(从左向右数,同一个格子内的球按照编号从小到大排序)

    枚举对应的位置$i$,再枚举$i$左侧/上/右侧的球数量$x,y$和$z$(要求$x+y+z=k$且$x<val\le x+y$),选择球的方案数即${k\choose x,y,z}$,同时操作的方案数即
    $$
    \sum_{\begin{array}&u_{1},u_{2},...,u_{x}<i\\v_{1},v_{2},...,v_{z}>i\\\sum u_{j}+\sum v_{j}+iy=nk-pos\end{array}}
    {nk-pos\choose u_{j},v_{j},i,i,...,i}
    {pos-1\choose n-u_{j},n-v_{j},n-i-1,n-i,n-i,....,n-i}
    $$
    (其中左侧$i$的数量为$y$,右侧$n-i$的数量为$y-1$)

    将累加的部分展开,提取常数项后也即$\prod_{j=1}^{x}\frac{1}{u_{j}!(n-u_{j})!}\prod_{j=1}^{z}\frac{1}{v_{j}(n-v_{j})!}$

    用$f_{i,j,k}$表示选择$j$个$[0,i)$之间的数$x$和为$k$的$\prod \frac{1}{x!(n-x)!}$​之和,进而该式也即
    $$
    \sum_{s=0}^{(i-1)x}f_{i,x,s}f_{n-i,y,s+iy+nz-nk+pos}
    $$
    关于$f_{i,j,k}$​的转移,考虑枚举最后一个数,显然即
    $$
    f_{i,j,k}=\sum_{x=0}^{i-1}\frac{f_{i,j-1,k-x}}{x!(n-x)!}
    $$
    预处理$f_{i,j,k}$的复杂度为$o(n^{3}k^{2})$,对于确定的$pos$和$val$计算$f(pos,val)$的复杂度为$o(n^{2}k^{3})$,由于有$n^{2}k$组,因此总复杂度为$o(n^{4}k^{4})$,无法通过

    进一步的,注意到$s$的枚举中,后式仅取决于$i,x,z$和$iy+nz-nk+pos$,预处理复杂度为$o(n^{3}k^{4})$,然后即可$o(1)$求出,单次复杂度降为$o(nk^{2})$,总复杂度降为$o(n^{3}k^{4})$(预处理),可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 25
     4 #define M 405
     5 #define ll long long
     6 int n,m,mod,fac[M],inv[M],mi[N][N],f[N][N][M<<1],g[N][N][N][M<<1];
     7 int calc(int pos,int val){
     8     int ans=0;
     9     for(int i=0;i<n;i++)
    10         for(int x=0;x<val;x++)
    11             for(int y=val-x;x+y<=m;y++){
    12                 int z=m-x-y,d=i*y+n*z-n*m+pos,s=g[i][x][z][d+n*m];
    13                 s=(ll)s*fac[m]%mod*inv[x]%mod*inv[y]%mod*inv[z]%mod;
    14                 s=(ll)s*mi[i][y]%mod*mi[n-i][y-1]%mod;
    15                 s=(ll)s*fac[n*m-pos]%mod*fac[pos-1]%mod*inv[n-i-1]%mod;
    16                 ans=(ans+s)%mod;
    17             }
    18     return ans;
    19 }
    20 int main(){
    21     scanf("%d%d%d",&n,&m,&mod);
    22     fac[0]=inv[0]=inv[1]=1;
    23     for(int i=1;i<M;i++)fac[i]=(ll)fac[i-1]*i%mod;
    24     for(int i=2;i<M;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
    25     for(int i=1;i<M;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
    26     for(int i=0;i<=n;i++){
    27         mi[i][0]=1;
    28         for(int j=1;j<=m;j++)mi[i][j]=(ll)mi[i][j-1]*inv[i]%mod;
    29     }
    30     for(int i=0;i<=n;i++)f[i][0][0]=1;
    31     for(int i=1;i<=n;i++)
    32         for(int j=1;j<=m;j++)
    33             for(int k=0;k<=n*m;k++)
    34                 for(int x=0;x<i;x++)
    35                     if (x<=k)f[i][j][k]=(f[i][j][k]+(ll)inv[x]*inv[n-x]%mod*f[i][j-1][k-x])%mod;
    36     for(int i=0;i<n;i++)
    37         for(int x=0;x<=m;x++)
    38             for(int z=0;x+z<=m;z++)
    39                 for(int d=-n*m;d<=n*m;d++){
    40                     int ans=0;
    41                     for(int s=max(-d,0);s<=(i-1)*x;s++)ans=(ans+(ll)f[i][x][s]*f[n-i][z][s+d])%mod;
    42                     g[i][x][z][d+n*m]=ans;
    43                 }
    44     for(int pos=1;pos<=n*m;pos++){
    45         for(int val=1;val<=m;val++)printf("%d ",calc(pos,val));
    46         putchar('\n');
    47     }
    48     return 0;
    49 } 
    View Code
  • 相关阅读:
    html表单的创建
    mysql数据库连接标准操作
    关于Apache+MySQL+PHP下载及配置注意事项
    两个范例
    Stack类
    Collections类集
    key可以重复的map集合:IdentityHashMap
    foreach对集合的输出作用
    ListIterator接口
    【官方方法】xcode7免证书真机调试
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15674590.html
Copyright © 2011-2022 走看看