51NOD 1934:受限制的排列——题解
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1934
听说会笛卡尔树的人这题都秒了啊……
参考:https://blog.csdn.net/vectorxj/article/details/79475244
首先题得看懂(我就是看题解才看懂题面的……),它告诉你对于i,我们有最大的(li,ri)使得这个区间内pi最小。
于是最小的数一定是(1,n)区间内的,设为pos,那么我们只需要递归处理(1,pos-1)和(pos+1,n)的即可。
当然我们的情况数要乘以给左区间的数的情况数。
中途如果出现各种无解情况直接返回0即可。
注意读入优化!
#include<map> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; struct fastio{ static const int bs=1000000; char c(){ static char buf[bs],*S=buf,*T=buf; if(S==T){ T=(S=buf)+fread(buf,1,bs,stdin); if(S==T)return EOF; } return *S++; } int operator()(){ int X=0;char ch=c(); if(ch==EOF)return 0; while(!isdigit(ch))ch=c(); while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=c(); return X; } }read; const int N=1e6+5; const int p=1e9+7; inline int qpow(int k,int n){ int res=1; while(n){ if(n&1)res=(ll)res*k%p; k=(ll)k*k%p;n>>=1; } return res; } map<int,int>mp[N]; int n,cnt,l[N],r[N]; int jc[N],inv[N]; void init(int k){ jc[0]=1; for(int i=1;i<=k;i++)jc[i]=(ll)jc[i-1]*i%p; inv[k]=qpow(jc[k],p-2); for(int i=k-1;i;i--)inv[i]=(ll)inv[i+1]*(i+1)%p; inv[0]=1; } inline int C(int a,int b){ return (ll)jc[a]*inv[b]%p*inv[a-b]%p; } int work(int L,int R){ if(L>R)return 1; int pos=mp[L][R]; if(L==pos&&pos==R)return 1; if(pos<L||R<pos)return 0; return (ll)C(R-L,pos-L)*work(L,pos-1)%p*work(pos+1,R)%p; } int main(){ init(1e6); while(n=read()){ for(int i=1;i<=n;i++)mp[i].clear(); for(int i=1;i<=n;i++)l[i]=read(); for(int i=1;i<=n;i++)r[i]=read(); bool flag=1; for(int i=1;i<=n;i++){ if(mp[l[i]].count(r[i]))flag=0; mp[l[i]][r[i]]=i; } if(!flag)printf("Case #%d: 0\n",++cnt); else printf("Case #%d: %d\n",++cnt,work(1,n)); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++