B4321 queue2 dp

这个题的dp真的恶心。首先,一开始我以为是一道数论题,但是组合数和这个题没啥关系。dp方程巨麻烦,状态是dp[i][j][0/1],代表i位连了j个,上一位是否连着。然后开始转移,证明如下:

我们先来分析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[i1][j1][1]+f[i1][j][1]+f[i1][j1][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)
综合

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)

很难推的题呀。。。。

题干:

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

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

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

Sample Input
4               
Sample Output
2 

样例解释:有两种方案 2 4 1 33 1 4 2 
HINT

Source

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
const int mod = 7777777;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
ll dp[1010][1010][3];
int main()
{
    int n;
    read(n);
    dp[1][0][0] = 1;
    duke(i,2,n)
    {
        duke(j,0,i)
        {
            dp[i][j][1] = (dp[i - 1][j - 1][1] + dp[i - 1][j][1] + dp[i - 1][j - 1][0] * 2) % mod;
            dp[i][j][0] = (dp[i - 1][j][0] * (i - j - 2) + dp[i - 1][j + 1][1] * j + dp[i - 1][j + 1][0] * (j + 1) + dp[i - 1][j][1] * (i - j - 1)) % mod;
        }
    }
    printf("%lld\n",dp[n][0][0]);
    return 0;
}

 

posted @ 2018-08-25 23:14  DukeLv  阅读(377)  评论(0编辑  收藏  举报