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; }