【bzoj4321】queue2 dp

题目描述

n 个沙茶,被编号 1~n。排完队之后,每个沙茶希望,自己的相邻的两人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行; 
现在想知道,存在多少方案满足沙茶们如此不苛刻的条件。 

输入

只有一行且为用空格隔开的一个正整数 N,其中 100%的数据满足 1≤N ≤ 1000; 

输出

一个非负整数,表示方案数对 7777777 取模。   

样例输入

4

样例输出


题解

dp

老套路了,考虑把数从小到大插入的过程进行dp。

设 $f[i][j]$ 表示 $1\sim i$ 的排列,有 $j$ 组相邻的相差1,且 $i$ 和 $i-1$ 不相邻的方案数;
设 $g[i][j]$ 表示 $1\sim i$ 的排列,有 $j$ 组相邻的相差1,且 $i$ 和 $i-1$ 相邻的方案数。

那么考虑插入 $i+1$ 的位置,有:不破坏空位且不与 $i$ 相邻、不破坏空位且与 $i$ 相邻、破坏空位且不与 $i$ 相邻、破坏空位且与 $i$ 相邻(只发生在 $g$ 的转移)4种。分别推一下方案数即可。

最后的答案就是 $f[n][0]$ 。

时间复杂度 $O(n^2)$ 。

另外把前几项丢到oeis上可以得到线性递推式 $a_n=(n+1)a_{n-1}-(n-2)a_{n-2}-(n-5)a_{n-3}+(n-3)a_{n-4}$ ,就能 $O(n)$ 求解了,感觉像是某容斥然而并不能推出来...

#include <cstdio>
#define mod 7777777
long long f[1010][1010] , g[1010][1010];
int main()
{
	int n , i , j;
	scanf("%d" , &n);
	f[1][0] = 1;
	for(i = 1 ; i < n ; i ++ )
	{
		for(j = 0 ; j < i ; j ++ )
		{
			f[i + 1][j] = (f[i + 1][j] + f[i][j] * (i - j - 1)) % mod;
			g[i + 1][j + 1] = (g[i + 1][j + 1] + f[i][j] * 2) % mod;
			if(j) f[i + 1][j - 1] = (f[i + 1][j - 1] + f[i][j] * j) % mod;
			f[i + 1][j] = (f[i + 1][j] + g[i][j] * (i - j)) % mod;
			g[i + 1][j + 1] = (g[i + 1][j + 1] + g[i][j]) % mod;
			if(j) f[i + 1][j - 1] = (f[i + 1][j - 1] + g[i][j] * (j - 1)) % mod;
			g[i + 1][j] = (g[i + 1][j] + g[i][j]) % mod;
		}
	}
	printf("%lld\n" , f[n][0]);
	return 0;
}

 

 

posted @ 2018-03-14 08:06  GXZlegend  阅读(524)  评论(2编辑  收藏  举报