BZOJ4321: queue2 dp

按照套路,考虑将数字从小到大插入到序列中.

令 $f[i][j]$ 表示将 $1$ ~ $i$ 插入到序列中,形成了 $j$ 对不合法的方案数.

然后考虑将 $i+1$ 插入时的情况:

1. 插入到不合法的空位中,消掉一个不合法.
2. 插入到合法的空位中
3. 插入到 $i$ 旁边,形成一个不合法.
4. 插入到 $i$ 与 $i-1$ 的空位中,消掉一个不合法,又新形成一个不合法.

我们发现,用 $f$ 不能很好地维护以上 4 中情况,所以引入 $g[i][j]$ 表示 $i$ 与 $i-1$ 相邻,并把 $f$ 的定义改成强制 $i$ 与 $i-1$ 不相邻即可.

细节什么的要提前想清楚,最好多验算几遍,可以减少调试时间.  

code:  

#include <bits/stdc++.h>   
#define ll long long 
#define mod 7777777
#define N 1009   
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int f[N][N],g[N][N],n;  
int main() 
{ 
    // setIO("input");                    
    f[1][0]=1,g[1][0]=0,g[2][1]=2;   
    scanf("%d",&n);   
    for(int i=3;i<=n;++i) 
    {
        for(int j=0;j<i;++j)   
        {    
            f[i][j]=(ll)((ll)f[i-1][j+1]*(j+1)%mod+(ll)g[i-1][j+1]*j%mod)%mod;        
            g[i][j]=(ll)(g[i-1][j]+g[i-1][j-1])%mod;  
            if(j) (g[i][j]+=(ll)2*f[i-1][j-1]%mod)%=mod;    
            if(i-j-2>0) (f[i][j]+=(ll)f[i-1][j]*(i-j-2)%mod)%=mod;    
            if(i-j-1>0) (f[i][j]+=(ll)g[i-1][j]*(i-j-1)%mod)%=mod;      
        }
    } 
    printf("%d\n",f[n][0]);   
    return 0; 
}

  

posted @ 2020-06-09 21:07  EM-LGH  阅读(117)  评论(0编辑  收藏  举报