问题 J: queue2
时间限制: 1 Sec 内存限制: 128 MB
题目描述
n 个沙茶,被编号 1~n。排完队之后,每个沙茶希望,自己的相邻的两
人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行;
现在想知道,存在多少方案满足沙茶们如此不苛刻的条件。
输入
只有一行且为用空格隔开的一个正整数 N,其中 100%的数据满足 1≤N ≤ 1000;
输出
一个非负整数,表示方案数对 7777777 取模。
样例输入
4
样例输出
2
样例解释:有两种方案 2 4 1 3 和 3 1 4 2
尝试自己想,列了f[i][j]表示选了前i个,有j个位置不符合,但是如何处理i和i+1的位置关系很麻烦。看题解加了一维。f[i][j][0/1]最后一维表示i和i-1是否相邻。
f[i][j][1]:+=f[i-1][j-1][0],i-1和i-2不相邻,故i放在i-1那一侧都会对答案有1的贡献。
+=f[i-1][j][1]+f[i-1][j-1][1],现在i-1和i-2相邻,如果i放在i-1和i-2相交一侧,i-1和i-2就不再相邻。反正,i-1和i-2继续相邻。
f[i][j][0]:+=f[i-1][j][1]*(i-j-1)共有i个位置,有j个位置不能选(不能拆散任何一对),i-1左右两个位置不能选,但有一个位置和那j个重了,所以剩下i-j-1个。
+=f[i-1][j][0]*(i-j-2)同理。
+=f[i-1][j+1][0]*(j+1)要拆散一对
+=f[i-1][j+1][1]*j 拆一对,但不能拆i-1和i-2
#include <cstdio>
#define mod 7777777
#define ll long long
int n;ll f[2][1105][2];
int main()
{
scanf("%d",&n);f[1][0][0]=1;
for(int i=2;i<=n;i++)
for(int j=0,x=i&1;j<i;j++)
{
f[x][j][1]=f[x^1][j][1];
if(j)(f[x][j][1]+=(f[x^1][j-1][1]+f[x^1][j-1][0]*2ll))%=mod;
f[x][j][0]=(f[x^1][j][1]*(i-j-1ll)+f[x^1][j][0]*(i-j-2ll)+f[x^1][j+1][1]*j+f[x^1][j+1][0]*(j+1ll))%mod;
}
printf("%lld\n",f[n&1][0][0]%mod);
}