题目描述

现在有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


题解

看了之后好懵逼啊……看了网上的题解,稍微理解了。

这道题主要的思路是区间DP。每次把两个相同的数字填进已有的序列[l, r]中。

但是由于题目中有这些限制,显然不能瞎填对吧……那么怎么判断能不能这样填呢?

方便起见,从大到小、从中间到两边填(因为原题要求中间比两边大)。

既然后填的、两边的数一定比先填的、中间的数小,那么只需判断当前要填的位置是否有“大于、大于等于、或等于已经填的区间内的元素”的限制就好了。另外,当前填的两个元素中,不能有“一个大于另一个”的限制。

具体来说,如果用dp[i][j]表示填满区间[i, j]的方案数,check(a, b, l, r) == 1 表示a、b不会“大于、大于等于、或等于[l, r]内的元素”且没有"a>b“或”b>a"的限制。

那么:

若都填到左边: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]

若两边各填一个: if(check(i, j, i + 1, j - 1)) dp[i][j] += dp[i + 1][j - 1]

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
bool read(T &x){
char c;
bool minus = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') minus = 1;
else if(c == EOF) return 0;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(minus) x = -x;
return 1;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} 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(){
read(n), read(k);
int a, b;
char sig[2];
while(k--){
sig[0] = sig[1] = 0;
read(a), scanf("%s", sig), read(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 0;
for(int i = 1; i <= leq[a][0]; i++)
if(leq[a][i] <= r && leq[a][i] >= l)
return 0;
for(int i = 1; i <= equ[a][0]; i++)
if(equ[a][i] <= r && equ[a][i] >= l)
return 0;
return 1;
}
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];
}
write(dp[1][2 * n]), enter;
return 0;
}

51nod 1522 上下序列的更多相关文章

  1. 51Nod 1522 上下序列 —— 区间DP

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1522 区间DP,从大往小加: 新加入一种数有3种加法:全加左边,全 ...

  2. $51nod\ 1522$ 上下序列 $dp$

    正解:$dp$ 解题报告: 传送门$QwQ$ 一年过去了$gql$还是不咋会这题,,,好菜昂我的$NOIp$必将惨败了$kk$ 考虑从大到小枚举两个相同的数填哪儿,根据那个限制,十分显然的是这两个数必 ...

  3. 51 nod 1522 上下序列——序列dp

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1522 很好的思想.考虑从小到大一对一对填数,这样也能对它的大小限制 ...

  4. 51nod 1476 括号序列的最小代价(贪心+优先队列)

    题意 我们这有一种仅由"(",")"和"?"组成的括号序列,你必须将"?"替换成括号,从而得到一个合法的括号序列. 对于 ...

  5. 【51nod】1822 序列求和 V5

    题解 我是zz吧 nonprime[i * prime[j]] = 0 = = 还以为是要卡常,卡了半天就是过不掉 我们来说这道题-- 首先,我们考虑一个\(K^2\)做法 \(f_{k}(N) = ...

  6. 51nod 1251 Fox序列的数量 (容斥)

    枚举最多数字的出现次数$k$, 考虑其他数字的分配情况. 对至少$x$种数出现$\ge k$次的方案容斥, 有 $\sum (-1)^x\binom{m-1}{x}\binom{n-(x+1)k+m- ...

  7. 胡小兔的OI日志3 完结版

    胡小兔的 OI 日志 3 (2017.9.1 ~ 2017.10.11) 标签: 日记 查看最新 2017-09-02 51nod 1378 夹克老爷的愤怒 | 树形DP 夹克老爷逢三抽一之后,由于采 ...

  8. 51nod 1258 序列求和 V4

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1258 1258 序列求和 V4  基准时间限制:8 秒 空间限制:131 ...

  9. 51NOD 1400 序列分解

    传送门:1400 序列分解序列分解 基准时间限制:1s  空间限制:131072 KBKB131072 KB 1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题1 秒 空间限制:13 ...

随机推荐

  1. 关于javascript原型链的个人理解

    首先js是一种面对对象的语言,虽然大多数时候是以面对过程的形式展现出来.先来看一段代码: function Base() { this.name = 'tarol'; } function Sub() ...

  2. 用GDI+画验证码

    1.新建一个窗体应用程序,在上面拖一个pictureBox对象,为其添加单击事件 2.创建GDI对象.产生随机数画入图片中.画线条.最后将图片到pictureBox中,代码如下: private vo ...

  3. [转载]GIF、JPEG 和 PNG的区别在哪里?

    原文地址:GIF.JPEG 和 PNG的区别在哪里?作者:苗得雨 GIF.JPEG 和 PNG 是三种最常见的图片格式. GIF:1987 年诞生,常用于网页动画,使用无损压缩,支持 256 种颜色( ...

  4. 201521123002《Java程序设计》第11周学习总结

    作业参考文件 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5 ...

  5. 解决vsftp无法启动问题(转)

    [root@node11 ~]# service vsftpd restartShutting down vsftpd:                                      [F ...

  6. JavaEE error整理(不断更新)

    该文章用于整理开发中遇到的一些错误,及解决方法,不断整理更新. 1. 缺包异常 异常1:java.lang.NoClassDefFoundError: org/apache/commons/loggi ...

  7. 创建maven项目pom.xml第一行报错

    之前也创建过几次maven项目,也是第一行报错,之前直接是右键项目强制更新maven好像就解决了,这次遇见这个问题使用这个方法好像不起作用了,给的一堆英文报错又看不懂,幸好在网上看见路人甲大神提示,根 ...

  8. [05] 利用private来封装

    我们知道,面向对象开发的三大特点是:封装性.继承性.多态性 所谓封装性,实际上是表达了一种信息隐藏.从表面上来阐述,就是使用private修饰符来对属性或者方法进行信息隐藏,而使用public的方法控 ...

  9. Spring写第一个应用程序

    ref:http://www.importnew.com/13246.html 让我们用Spring来写第一个应用程序吧. 完成这一章要求: 熟悉Java语言 设置好Spring的环境 熟悉简单的Ec ...

  10. CyclicBarrier的使用之王者荣耀打大龙

    最近一直整并发这块东西,顺便写点Java并发的例子,给大家做个分享,也强化下自己记忆,如果有什么错误或者不当的地方,欢迎大家斧正. LOL和王者荣耀的玩家很多,许多人应该都有打大龙的经历,话说前期大家 ...