DP,状态想了很久……
设 f[i][j][0..1] 表示前i个沙茶有j对是相邻的,其中第i个沙茶和第i-1个沙茶相不相邻。
先考虑第i个沙茶和第i-1个沙茶相邻, f[i][j][1] 。现在第i个沙茶是新插入进去的,他的插♂入直接导致了他和第i-1个沙茶牵手了(雾),他可以牵第i个沙茶的左手或右手。如果原本第i-1个沙茶和第i-2个沙茶是牵手的,而当前这个沙茶插进去之后强行让他们分手自己再插进去,这就是 f[i−1][j][1] ,即相邻的沙茶对数仍然是j。又或者他们(哔~),当前沙茶和第i-1个沙茶牵手却不影响第i-2个沙茶,导致沙茶的对数增加了1,即原来是 f[i−1][j−1][1] 。还有的情况就是第i-1个沙茶没有和第i-2个沙茶牵手,当前沙茶既可以牵他左手又可以牵右手,即为 f[i−1][j−1][0]∗2
故 f[i][j][1]=f[i−1][j][1]+f[i−1][j−1][1]+f[i−1][j−1][0]∗2
再考虑第i个沙茶和第i-1个沙茶不相邻, f[i][j][0] 。
单身狗总是想FFF恩爱狗嘛~
当前的沙茶可以选择在第i-1个沙茶和第i-2个沙茶牵手或不牵手的时候去拆散别人,那么分别有 f[i−1][j+1][1]∗j 和 f[i−1][j+1][0]∗(j+1) 种选择。又或者他是个好人,一定不会去拆散他们,那么就有 f[i−1][j][1]∗(i−j−1) 和 f[i−1][j][0]∗(i−j−2) 种选择。
故 f[i][j][0]=f[i−1][j+1][1]∗j+f[i−1][j+1][0]∗(j+1)+f[i−1][j][1]∗(i−j−1)+f[i−1][j][0]∗(i−j−2)
时间 O(n2) ,如果用滚动数组空间就是 O(n) 。
然而我太懒没有写滚动>_<
另外……
http://oeis.org/A002464
咳咳。
fn=(n+1)fn−1−(n−2)fn−2−(n−5)fn−3+(n−3)fn−4
我也不知道为什么
学长说可能是容斥的。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * + c - '0';
return x;
}
typedef long long ll;
const int mod = ;
inline void upd(int&a , ll b) { if (b >= mod) b %= mod ; a += b ; if (a >= mod) a -= mod ; }
int n , f[][][];
void input() {
n = rd();
}
void solve() {
f[][][] = ;
rep(i , , n) rep(j , , i - ) {
f[i][j][] = f[i - ][j][];
if (j) upd(f[i][j][] , f[i - ][j - ][] * l + f[i - ][j - ][]);
upd(f[i][j][] , (ll) f[i - ][j + ][] * j);
upd(f[i][j][] , (ll) f[i - ][j + ][] * (j + ));
upd(f[i][j][] , (ll) f[i - ][j][] * (i - j - ));
upd(f[i][j][] , (ll) f[i - ][j][] * (i - j - ));
}
printf("%d\n" , f[n][][]);
}
int main() {
#ifndef ONLINE_JUDGE
// freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return ;
}