BZOJ4321 queue2
Description
求1~n的序列,满足一个数的左右两边的差的绝对值不等与1的方案数。
对答案mod 7777777
题解
很奇怪的状态,看了题解才搞懂。
钦定f[i][j][1]表示推到第i个数,其中有j对数是相差1的,其中i,与i-1相邻
f[i][j][0]表示推到第i个数,其中有j对数是相差1的,其中i,与i-1不相邻。
我们先来分析i-1,i相邻,也就是f[i][j][1]怎么推。
对于i,i-1,i-2,有这几种关系,
本来i-1与i-2相邻,将i插入两者中,拆了一对(i-1,i-2),又形成了一对(i-1,i),这样方案来源于f[i-1][j][1]。
本来i-1与i-2相邻,将i插入与i-1相邻却不被i-1与i-2夹着,多形成了一对(i-1,i),这样方案来源于f[i-1][j-1][1]。
本来i-1与i-2不相邻,将i插入与i-1相邻,形成了一对(i-1,i),这样方案来源于f[i-1][j-1][1],由于i-1的左右够可以插,方案就乘2。
这样
f[i][j][1]=f[i−1][j−1][1]+f[i−1][j][1]+f[i−1][j−1][0]∗2
关于i-1,i不相邻,也就是f[i][j][0]怎么推
本来i-1与i-2相邻,将i插入j对相邻的数的任意一对,这样就破坏了一对,这样方案来源于f[i-1][j+1][1],有(j+1-1)种位置可以选(i-1与i-2那对不能拆,因为插入又会形成新的)。
本来i-1与i-2不相邻,将i插入j对相邻的数的任意一对,这样就破坏了一对,这样方案来源于f[i-1][j+1][0],有(j+1)种位置可以选。
又可能i不去拆开相邻的数,就可以来源于
f[i-1][j][1]*(i-j-1)(可以插入i-1与i-2,不改变对数) 或 f[i-1][j][0]*(i-j-2)
综合
很难推的题呀。。。。
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#define MAXN 1000+10
#define LL long long
#define MOD 7777777
using namespace std;
LL f[MAXN][MAXN][2],n;
int main()
{
scanf("%lld",&n);
f[1][0][0]=1;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
f[i][j][1]=(f[i-1][j][1]+f[i-1][j-1][1]+f[i-1][j-1][0]*2)%MOD;
f[i][j][0]=(f[i-1][j+1][1]*j+f[i-1][j+1][0]*(j+1))%MOD;
f[i][j][0]=(f[i][j][0]+f[i-1][j][1]*(i-j-1)+f[i-1][j][0]*(i-j-2))%MOD;
}
}
printf("%lld\n",f[n][0][0]);
return 0;
}