numbers

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 196608/196608 K (Java/Others)
Total Submission(s): 154    Accepted Submission(s): 46

Problem Description
Now you have a stack and n numbers 1,2,3,…,n. These n numbers are pushed in the order and popped if the number is at the top of the stack. You can read the sample to get more details.
This question is quite easy. Therefore I must give you some limits.
There are m limits, each is expressed as a pair<A,B> means the number A must be popped before B.
Could you tell me the number of ways that are legal in these limits?
I know the answer may be so large, so you can just tell me the answer mod 1000000007(109+7).
Input
The first line contains an integer T(about 5),indicating the number of cases.
Each test case begins with two integers n(1≤n≤300) and m(1≤m≤90000).
Next m lines contains two integers A and B(1≤A≤n,1≤B≤n)
(P.S. there may be the same limits or contradict limits.)
Output
For each case, output an integer means the answer mod 1000000007.
Sample Input
5
1 0
5 0
3 2
1 2
2 3
3 2
2 1
2 3
3 3
1 2
2 3
3 1
Sample Output
1
42
1
2
0

Hint

The only legal pop-sequence of case 3 is 1,2,3.
The legal pop-sequences of case 4 are 2,3,1 and 2,1,3.

Source
题目大意:一个由1,2,......,n组成的排列,顺次插入栈中,你可以选择在任意时刻弹出栈顶元素,现在有m个要求,要求x必须在y之前出栈,问有多少种合法的出栈顺序.
分析:好题!
   先考虑没有要求的情况. 很显然就是卡特兰数. 可以用区间dp的方法去做:f[i][j] = Σf[i][k - 1] * f[k + 1][j],枚举的k是区间[i,j]中最后被弹出的元素,那么肯定先是区间[i,k-1]的元素被弹出,然后就是区间[k+1,j]的元素被弹出,最后是k被弹出.这是O(n^3)的做法
   如果有限制怎么办呢?能不能在原有的dp方案的基础上改进一下呢? 可以往两个方向思考,要么是给状态加上一维,要么是就沿用这个状态,把不满足限制的方案给排除掉. 加上一维是不现实的,因为复杂度已经达到了O(n^3),加上一维的话复杂度肯定会再上升一个级别.
   那就考虑如何把不满足限制的方案给排除掉.假设x必须要在y之前弹出,令x,y的较小值为min,较大值为max.对于x,y的限制,影响的只有包含x,y这两个点的区间,也就是区间左端点在[1,min],右端点在[max,n]的区间. 
   若x < y,那么x在排列中的位置肯定在y前面.前面说过元素弹出的顺序,如果k在x,y右边或者左边,那么作为一个子问题已经被解决了.如果k在x,y中间.只要k不是x,x永远比y先弹出. 那么对于被x,y影响的区间,一旦k = x,就不能统计进入答案中.
   若x > y,y在左边了.考虑k在y,x中间的情况.k 可以等于 y,这样y在x之后被弹出,但是一旦 y + 1 ≤ k ≤ x,则k是不合法的.
   预处理出不合法的状态是O(n^2m)的复杂度,显然是不可以接受的,怎么优化呢?
   k是要枚举的,但是区间的左右端点所在的区间是确定的,需要做的就是把这些区间快速打上标记.做法还是比较难想到的.
不合法的区间形如:[1,max],[1,max + 1],......,[1,n],[2,max],[2,max + 1],......,[min,n]. 对于二元组,一个处理方法是放到平面直角坐标系上,然后可以发现,这些点所形成的图形是一个矩形. 批量修改一个矩形,怎么快速改? 二维差分!怎么查询单个点的答案?前缀和!问题就这样被解决了.
   总复杂度O(n^3 + n*m).
   这道题综合了许多知识,把问题简化,得到一个做法后该如何推导出原问题的做法?能不能用上简化的问题的做法?如何快速修改左右端点所在区间都知道的所有区间?遇到二元组要怎么处理?如何快速修改一个矩形内所有点的值?如何查询单点答案?这就是这道题的思路.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; typedef long long ll;
const ll maxn = ,mod = 1e9+;
ll f[maxn][maxn];
int T,n,m,sum[maxn][maxn][maxn],a[maxn][maxn][maxn];
bool flag = true; struct node
{
int x,y;
} e[]; void add(int x3,int y3,int x4,int y4,int k)
{
sum[x3][y3][k]++;
sum[x4 + ][y4 + ][k]++;
sum[x4 + ][y3][k]--;
sum[x3][y4 + ][k]--;
} void pre()
{
for (int i = ; i <= m; i++)
{
ll x = e[i].x,y = e[i].y;
if (x < y)
add(,y,x,n,x);
else
{
for (int j = y + ; j <= x; j++)
add(,x,y,n,j);
}
}
for (int k = ; k <= n; k++)
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
sum[i][j][k] = sum[i - ][j][k] + sum[i][j - ][k] - sum[i - ][j - ][k] + sum[i][j][k];
} void solve()
{
for (int i = ; i <= n; i++)
{
f[i][i] = ;
f[i][i - ] = ;
}
f[n + ][n] = ;
for (int len = ; len <= n; len++)
for (int i = ; i + len - <= n; i++)
{
int j = i + len - ;
for (int k = i; k <= j; k++)
{
if (sum[i][j][k] == )
{
f[i][j] += f[i][k - ] * f[k + ][j] % mod;
f[i][j] %= mod;
}
}
}
} int main()
{
scanf("%d",&T);
while(T--)
{
memset(sum,,sizeof(sum));
memset(f,,sizeof(f));
flag = true;
scanf("%d%d",&n,&m);
for (ll i = ; i <= m; i++)
{
scanf("%d%d",&e[i].x,&e[i].y);
if (e[i].x == e[i].y)
flag = false;
}
if (!flag)
puts("");
else
{
pre();
solve();
printf("%lld\n",f[][n] % mod);
}
} return ;
}
   

Hdu5181 numbers的更多相关文章

  1. Java 位运算2-LeetCode 201 Bitwise AND of Numbers Range

    在Java位运算总结-leetcode题目博文中总结了Java提供的按位运算操作符,今天又碰到LeetCode中一道按位操作的题目 Given a range [m, n] where 0 <= ...

  2. POJ 2739. Sum of Consecutive Prime Numbers

    Sum of Consecutive Prime Numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20050 ...

  3. [LeetCode] Add Two Numbers II 两个数字相加之二

    You are given two linked lists representing two non-negative numbers. The most significant digit com ...

  4. [LeetCode] Maximum XOR of Two Numbers in an Array 数组中异或值最大的两个数字

    Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231. Find the maximum re ...

  5. [LeetCode] Count Numbers with Unique Digits 计算各位不相同的数字个数

    Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10n. Examp ...

  6. [LeetCode] Bitwise AND of Numbers Range 数字范围位相与

    Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers ...

  7. [LeetCode] Valid Phone Numbers 验证电话号码

    Given a text file file.txt that contains list of phone numbers (one per line), write a one liner bas ...

  8. [LeetCode] Consecutive Numbers 连续的数字

    Write a SQL query to find all numbers that appear at least three times consecutively. +----+-----+ | ...

  9. [LeetCode] Compare Version Numbers 版本比较

    Compare two version numbers version1 and version1.If version1 > version2 return 1, if version1 &l ...

随机推荐

  1. 爬虫2.4-scrapy框架-图片分类下载

    目录 scrapy框架-图片下载 1 传统下载方法: 2 scrapy框架的下载方法 3 分类下载完整代码 scrapy框架-图片下载 python小知识: map函数:将一个可迭代对象的每个值,依次 ...

  2. spring-boot 项目整合logback

    使用spring-boot项目中添加日志输出,java的日志输出一共有两个大的方案log4j/log4j2 ,logback.log4j2算是对log4j的一个升级版本. 常规做法是引入slf4j作为 ...

  3. [python]序列的重复操作符

    当你需要需要一个序列的多份拷贝时,重复操作符非常有用,它的语法如下: sequence * copies_int In [1]: a = [1,2,3,4] In [2]: a * 5 Out[2]: ...

  4. 数据挖掘学习笔记——kaggle 数据预处理

    预处理 1. 删除缺失值 a. 删除行即样本(对于样本如果输出变量存在缺失的则直接删除该行,因为无法用该样本训练) b. 删除列,即特征(采用这种删除方式,应保证训练集和验证集都应当删除相同的特征) ...

  5. mysql先删除后插入导致死锁

    所报的错误为:pymysql.err.OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting ...

  6. Python-2.7 配置tab自动补全功能

    作者博文地址:http://www.cnblogs.com/spiritman/ 之前一直使用shell编程,习惯了shell的 tab 自动补全功能,而Python的命令行却不支持 tab 自动补全 ...

  7. Python--matplotlib 绘图可视化练手--折线图/条形图

    最近学习matplotlib绘图可视化,感觉知识点比较多,边学习边记录. 对于数据可视化,个人建议Jupyter Notebook. 1.首先导包,设置环境 import pandas as pd i ...

  8. mininet实验 可视化界面形成拓扑

    参考博客一 参考博客二 实验目的 mininet中内置了一个mininet可视化工具:miniedit.miniedit在mininet/mininet/examples目录下提供miniedit.p ...

  9. 第二次c++作业

    用c语言实现电梯问题的方法: 先用一堆变量存储各种变量,在写一个函数模拟电梯上下移动载人放人的过程. c++: 构造一个电梯的类,用成员函数实现电梯运作的过程. 对c和c++的理解太浅,并没有感觉到用 ...

  10. 404 Note Found· 第七次作业 - 需求分析报告

    目录 组队后的团队项目的整体计划安排 项目logo及思维导图 项目logo 思维导图 产品思维导图 产品思维导图-引导 产品思维导图-后端数据处理.存储 产品思维导图-短信识别 产品思维导图-智能分析 ...