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

浙公网安备 33010602011771号