Hdoj 5181 numbers
numbers
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 196608/196608 K (Java/Others)
Total Submission(s): 156 Accepted Submission(s): 50
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({10}^{9}+7).
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({10}^{9}+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 \leq n \leq 300) and m(1 \leq m \leq 90000).
Next m lines contains two integers A and B(1 \leq A \leq n,1 \leq B \leq n)
(P.S. there may be the same limits or contradict limits.)
Each test case begins with two integers n(1 \leq n \leq 300) and m(1 \leq m \leq 90000).
Next m lines contains two integers A and B(1 \leq A \leq n,1 \leq B \leq 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
设f[i][j]为数字(i-j)的出栈方案数,显然我们可以枚举最后一个出栈的元素k,i<=k<=j。先把[i,k-1]出栈完了之后,把k放进去,然后再放[k+1,j]
并且出栈后再出k。
所以我们可以得到递推式 f[i][j]=Σf[i][k-1]*f[k+1][j] ,当然因为有限制这里的k显然不能取区间[i,j]的所有数。
当然A,B只能对 L<=min(A,B),R>=max(A,B)的f[L][R]产生影响。
我们发现当A<B时,只要k!=A就是合法的,因为出栈顺序是[i,k-1]->[k+1,j]->k;
而当A>B时,观察出栈顺序也可以发现只要k¢(B,A]就是合法的。
于是现在的问题变成了如何快速判断一个k在对于f[i][j]是否合法。。。。
我们可以发现的是,当把区间的左端点看成横坐标,区间的右端点看成纵坐标的时候,对于一组A、B
不合法的区域就是以(1,max(A,B))为左下角,(min(A,B),n)为右上角的矩形。
虽然这个坐标系只有在直线y=x上方的区域是有用的,但是我们不妨对每个k都做一遍差分,
然后再前缀和一下得到它在哪些区间是不合法的。
这样就可以 O(N^3 + N*M) 完成本题了。
#include<bits/stdc++.h> #define ll long long using namespace std; const int ha=1000000007; int f[305][305],n,m,T; int uu,vv,ban[305][305][305]; bool flag; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline void init(){ memset(f,0,sizeof(f)); memset(ban,0,sizeof(ban)); flag=0; } inline void matrix(int px1,int py1,int px2,int py2,int num){ ban[num][px1][py1]++; ban[num][px2+1][py1]--; ban[num][px1][py2+1]--; ban[num][px2+1][py2+1]++; } inline void dp(){ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) ban[i][j][k]+=ban[i][j-1][k]+ban[i][j][k-1]-ban[i][j-1][k-1]; for(int i=1;i<=n;i++) f[i][i]=f[i][i-1]=1; f[n+1][n]=1; for(int len=1;len<n;len++) for(int i=1,j;(j=i+len)<=n;i++) for(int k=i;k<=j;k++) if(!ban[k][i][j]){ f[i][j]=add(f[i][j],f[i][k-1]*(ll)f[k+1][j]%ha); } } int main(){ scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); while(m--){ scanf("%d%d",&uu,&vv); if(uu<vv){ matrix(1,vv,uu,n,uu); } else if(uu>vv){ for(int j=vv+1;j<=uu;j++) matrix(1,uu,vv,n,j); } else flag=1; } if(flag){ puts("0"); continue; } dp(); printf("%d\n",f[1][n]); } return 0; }
我爱学习,学习使我快乐