Limited Permutation
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6044
题意:现在有一个排列p1,p2,p3,p4,p5,p6…………pn,然后再给你n对区间[Li,Ri]【i表示第i个区间】。现在有一个这样的定义min(pL,pL+1,⋯,pR)=pi,也就是说对于第i个区间[Li,Ri]中最小的是一个pi,问这样的排列有多少个?
思路:我们先分析题目意思从min(pL,pL+1,⋯,pR)=pi中我们可以分析由于最终要确定这个排列所以必定存在一个区间是[1,n]这样才能确定最小的哪一位,假设这是第i组区间,就把整个[1,n]的区间分成两半,一个是[1,i-1].一个是[i+1,n],从而确定了最小的数1在第i个位置。对于两个子区间我们以[1,n-1]这个区间为例,我们是不是也需要一个区间刚好是[1,i-1]我们才能确定[1,i-1]这个区间内最小的那个值是哪一个。以此类推,又可以分成两个区间,右边的那个区间也是这样。所以我们可以的得到得到这样的一个结论,只要在这个分区间的过程中其中一个区间不存在,我就无法确定区间最小,也就无法形成一个区间,这个时候答案就是零。如果所有区间都存在着就是一个组合数的问题,我们思考对于[1,n]这个区间分成[1,i-1]和[i+1.n]两个区间对于左边区间是不是需要i-1个数,而总共是n-1个数,是不相当于乘以C(n-1,i-1)的组合数,然后进一步递归下去,链乘上分区间返回上来的组合数,还有右边返回上来的组合数这个具体看代码。
对于判断这个区间是否存在一开始的dfs,然后用map去判断结果超时了,可能是由于组合数取膜使用的乘法逆元是用快速幂求出来的,据说可以n的复杂度预处理逆元,不太会……所以超时了。后来发现一个规律,我们可以一开始的时候对于一个区间用以左节点升续排序,左节点相同以右节点的降序排列,这样就实际上就是一个dfs序,我们仔细分析我们之前操作。实际上就是一个dfs的过程,如果排列存在,那么我们在dfs过程中遇到的区间应该严格与我们排完序的区间吻合,如果不吻合,就说明区间不存在,可能不太好理解。自己模拟一遍这个dfs的过程就会明白了。
这道题还有一个究极输入挂:
代码:
const int MAXBUF = 10000; char buf[MAXBUF], *ps = buf, *pe = buf+1; inline void rnext() { if(++ps == pe) pe = (ps = buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin); } template <class T> inline bool readin(T &ans) { ans = 0; T f = 1; if(ps == pe) return false;//EOF do{ rnext(); if('-' == *ps) f = -1; }while(!isdigit(*ps) && ps != pe); if(ps == pe) return false;//EOF do { ans = (ans<<1)+(ans<<3)+*ps-48; rnext(); }while(isdigit(*ps) && ps != pe); ans *= f; return true; }
由于数据量很大,所以需要这个超级输入挂,没有这个输入挂是过不了的,可以记下来。
AC代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 0x3f3f3f3f 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define da cout<<da<<endl 19 #define uoutput(a,i,l,r) for(int i=l;i<r;i++) if(i==l) cout<<a[i];else cout<<" "<<a[i];cout<<endl; 20 #define doutput(a,i,l,r) for(int i=r-1;i>=0;i--) if(i==r-1) cout<<a[i];else cout<<" "<<a[i];cout<<endl; 21 const long long N= 1000000+10; 22 const long long mod=1e9+7; 23 using namespace std; 24 typedef long long LL; 25 LL mi[N]; 26 LL n,flag,ct; 27 struct node{ 28 LL x,y,z; 29 bool operator <(const node &m) const{ 30 if(x==m.x) return y>=m.y; 31 else return x<m.x; 32 } 33 }oj[N]; 34 LL q_power(LL a,LL k){ 35 LL ans=1; 36 while(k){ 37 if(k%2) ans=ans*a%mod; 38 k/=2; 39 a=a*a%mod; 40 } 41 return ans; 42 } 43 void init(){ 44 mi[1]=mi[0]=1; 45 for(int i=2;i<=N-1;i++){ 46 mi[i]=mi[i-1]*i%mod; 47 } 48 } 49 50 LL cal(LL a,LL b){ 51 LL ans=1; 52 ans=mi[a]*q_power(mi[a-b],mod-2)%mod; 53 ans=ans*q_power(mi[b],mod-2)%mod; 54 55 return ans; 56 } 57 LL dfs(LL x,LL y){ 58 if(flag) return 0; 59 if(x>y) return 1; 60 if(oj[ct].x!=x||oj[ct].y!=y){ 61 flag=1;return 0; 62 } 63 node t=oj[ct]; 64 ct++; 65 if(x==y) return 1; 66 LL res=cal(t.y-t.x,t.z-t.x)*dfs(t.x,t.z-1)%mod; 67 res=res*dfs(t.z+1,t.y)%mod; 68 return res; 69 } 70 71 const int MAXBUF = 10000; 72 char buf[MAXBUF], *ps = buf, *pe = buf+1; 73 74 inline void rnext() 75 { 76 if(++ps == pe) 77 pe = (ps = buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin); 78 } 79 80 template <class T> 81 inline bool readin(T &ans) 82 { 83 ans = 0; 84 T f = 1; 85 if(ps == pe) return false;//EOF 86 do{ 87 rnext(); 88 if('-' == *ps) f = -1; 89 }while(!isdigit(*ps) && ps != pe); 90 if(ps == pe) return false;//EOF 91 do 92 { 93 ans = (ans<<1)+(ans<<3)+*ps-48; 94 rnext(); 95 }while(isdigit(*ps) && ps != pe); 96 ans *= f; 97 return true; 98 } 99 int main() { 100 //freopen("data.txt","r",stdin); 101 init(); 102 int h=0; 103 while(readin(n)){ 104 for(int i=1;i<=n;i++) readin(oj[i].x); 105 for(int i=1;i<=n;i++) { 106 readin(oj[i].y); 107 oj[i].z=i; 108 } 109 flag=0;ct=1; 110 sort(oj+1,oj+n+1); 111 printf("Case #%d: %lld ",++h,dfs(1LL,n)); 112 } 113 return 0; 114 }