【bzoj4321】queue2

来源:互联网 发布:怎么用邮箱注册知乎 编辑:程序博客网 时间:2024/05/21 09:56

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[i1][j][1],即相邻的沙茶对数仍然是j。又或者他们(哔~),当前沙茶和第i-1个沙茶牵手却不影响第i-2个沙茶,导致沙茶的对数增加了1,即原来是f[i1][j1][1]。还有的情况就是第i-1个沙茶没有和第i-2个沙茶牵手,当前沙茶既可以牵他左手又可以牵右手,即为f[i1][j1][0]2

f[i][j][1]=f[i1][j][1]+f[i1][j1][1]+f[i1][j1][0]2

再考虑第i个沙茶和第i-1个沙茶不相邻,f[i][j][0]
单身狗总是想FFF恩爱狗嘛~
当前的沙茶可以选择在第i-1个沙茶和第i-2个沙茶牵手或不牵手的时候去拆散别人,那么分别有f[i1][j+1][1]jf[i1][j+1][0](j+1)种选择。又或者他是个好人,一定不会去拆散他们,那么就有f[i1][j][1](ij1)f[i1][j][0](ij2)种选择。

f[i][j][0]=f[i1][j+1][1]j+f[i1][j+1][0](j+1)+f[i1][j][1](ij1)+f[i1][j][0](ij2)

时间O(n2),如果用滚动数组空间就是O(n)

然而我太懒没有写滚动>_<

另外……

http://oeis.org/A002464
咳咳。
fn=(n+1)fn1(n2)fn2(n5)fn3+(n3)fn4
我也不知道为什么
学长说可能是容斥的。

#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 * 10 + c - '0';    return x;}typedef long long ll;const int mod = 7777777;inline void upd(int&a , ll b) { if (b >= mod) b %= mod ; a += b ; if (a >= mod) a -= mod ; }int n , f[1001][1001][2];void input() {    n = rd();}void solve() {    f[1][0][0] = 1;    rep(i , 2 , n) rep(j , 0 , i - 1) {        f[i][j][1] = f[i - 1][j][1];        if (j) upd(f[i][j][1] , f[i - 1][j - 1][0] * 2ll + f[i - 1][j - 1][1]);        upd(f[i][j][0] , (ll) f[i - 1][j + 1][1] * j);        upd(f[i][j][0] , (ll) f[i - 1][j + 1][0] * (j + 1));        upd(f[i][j][0] , (ll) f[i - 1][j][1] * (i - j - 1));        upd(f[i][j][0] , (ll) f[i - 1][j][0] * (i - j - 2));    }    printf("%d\n" , f[n][0][0]);}int main() {    #ifndef ONLINE_JUDGE    //  freopen("data.txt" , "r" , stdin);    #endif    input();    solve();    return 0;}
0 0
原创粉丝点击