51Nod - 1522 上下序列

现在有1到n的整数,每一种有两个。要求把他们排在一排,排成一个2*n长度的序列,排列的要求是从左到右看,先是不降,然后是不升。

特别的,也可以只由不降序列,或者不升序列构成。

例如,下面这些序列都是合法的:

·        [1,2,2,3,4,4,3,1];

·        [1,1];

·        [2,2,1,1];

·        [1,2,3,3,2,1].

除了以上的条件以外,还有一些其它的条件,形如"h[xi] signi h[yi]",这儿h[t]表示第t个位置的数字,signi是下列符号之一:'=' (相等), '<' (小于), '>' (大于), '<=' (小于等于), '>=' (大于等于)。这样的条件有k个。

请计算一下有多少种序列满足条件。

Input

单组测试数据。
第一行有两个整数 n 和k (1≤n≤35, 0≤k≤100),表示数字的种类和限制条件的数目。
接下来k行,每一行的输入格式是这样的:"xi signi yi" (1≤xi,yi≤2*n),signi是上面五种符号中的一种。

Output

输出一个整数,表示有多少种序列满足条件。

Input示例

样例输入1
3 0
样例输入2
3 1
2 > 3

Output示例

样例输出1
9
样例输出2
1

思路:

从大到小,每次放入两个相同的数:比如n=3时,先把两个3放进去,然后再放两个2,每次放的时候判断是否满足限制条件。注意放的位置有3种,左,中,右。

#include <iostream>
using namespace std;

typedef long long ll;
#define INF 0x3f3f3f3f

const int N = 80, K = 105;
int n, k;
int lar[N][K], leq[N][K], equ[N][K];
ll dp[N][N];

void init()
{
    cin >> n >> k;
    int a, b;
    char sig[2];
    while (k--)
    {
        sig[0] = sig[1] = 0;
        cin >> a >> sig >> b;
        if (sig[0] == '=')
        {
            equ[a][++equ[a][0]] = b;
            equ[b][++equ[b][0]] = a;
        }
        else
        {
            if (sig[0] == '<')
            {
                swap(a, b);
            }
            if (sig[1] == '=')
            {
                leq[a][++leq[a][0]] = b;
            }
            else
            {
                lar[a][++lar[a][0]] = b;
            }
        }
    }
}

bool single_check(int a, int b, int l, int r)
{
    for (int i = 1; i <= lar[a][0]; i++)
    {
        if ((lar[a][i] <= r && lar[a][i] >= l) || lar[a][i] == b)
        {
            return false;
        }
    }
    
    for (int i = 1; i <= leq[a][0]; i++)
    {
        if (leq[a][i] <= r && leq[a][i] >= l)
        {
            return false;
        }
    }
    for (int i = 1; i <= equ[a][0]; i++)
    {
        if (equ[a][i] <= r && equ[a][i] >= l)
        {
            return false;
        }
    }
    
    return true;
}

bool check(int a, int b, int l, int r)
{
    return single_check(a, b, l, r) && single_check(b, a, l, r);
}

int main()
{
    init();
    for (int i = 1; i < 2 * n; i++) 
    {
        if (check(i, i + 1, 0, 0)) 
        {
            dp[i][i + 1] = 1;
        }
    }
    for (int len = 2; len <= 2 * n; len += 2)
    {
        for (int i = 1; i + len - 1 <= 2 * n; i++)
        {
            int j = i + len - 1;
            if (check(i, j, i + 1, j - 1))
            {
                dp[i][j] += dp[i + 1][j - 1];
            }
            if (check(i, i + 1, i + 2, j))
            {
                dp[i][j] += dp[i + 2][j];
            }
            if (check(j - 1, j, i, j - 2))
            {
                dp[i][j] += dp[i][j - 2];
            }
        }
    }
    cout << dp[1][2 * n] << endl;
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值