51NOD 1934:受限制的排列——题解

时间:2025-03-03 18:07:56

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1934

听说会笛卡尔树的人这题都秒了啊……

参考:https://blog.****.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=;
char c(){
static char buf[bs],*S=buf,*T=buf;
if(S==T){
T=(S=buf)+fread(buf,,bs,stdin);
if(S==T)return EOF;
}
return *S++;
}
int operator()(){
int X=;char ch=c();
if(ch==EOF)return ;
while(!isdigit(ch))ch=c();
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=c();
return X;
}
}read;
const int N=1e6+;
const int p=1e9+;
inline int qpow(int k,int n){
int res=;
while(n){
if(n&)res=(ll)res*k%p;
k=(ll)k*k%p;n>>=;
}
return res;
}
map<int,int>mp[N];
int n,cnt,l[N],r[N];
int jc[N],inv[N];
void init(int k){
jc[]=;
for(int i=;i<=k;i++)jc[i]=(ll)jc[i-]*i%p;
inv[k]=qpow(jc[k],p-);
for(int i=k-;i;i--)inv[i]=(ll)inv[i+]*(i+)%p;
inv[]=;
}
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 ;
int pos=mp[L][R];
if(L==pos&&pos==R)return ;
if(pos<L||R<pos)return ;
return (ll)C(R-L,pos-L)*work(L,pos-)%p*work(pos+,R)%p;
}
int main(){
init(1e6);
while(n=read()){
for(int i=;i<=n;i++)mp[i].clear();
for(int i=;i<=n;i++)l[i]=read();
for(int i=;i<=n;i++)r[i]=read();
bool flag=;
for(int i=;i<=n;i++){
if(mp[l[i]].count(r[i]))flag=;
mp[l[i]][r[i]]=i;
}
if(!flag)printf("Case #%d: 0\n",++cnt);
else printf("Case #%d: %d\n",++cnt,work(,n));
}
return ;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++