题意
对于一个 1 到 n 的排列 p1,p2,⋯,pn ,我们可以轻松地对于任意的 1≤i≤n 计算出 (li,ri) ,使得对于任意的 1≤L≤R≤n 来说 min(pL,pL+1,⋯,pR)=pi 当且仅当 li≤L≤i≤R≤ri 。
给定整数 n 和 (li,ri) (1≤i≤n) ,你需要计算有多少种可能的 1 到 n 的排列 p1,p2,⋯,pn 满足上述条件。
由于答案可能很大,你只需要给出答案对 10^9+7 取模的值。
分析
辣鸡题目居然卡常,然而并没有松过去,最后只好交一个别人的程序过掉算了。
题目并不难,注意到这个区间实际上就是对这个排列建笛卡尔树后的中序遍历,那么分治算一下然后乘一下组合数就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#define mp(x,y) std::make_pair(x,y)
typedef long long LL;
typedef std::pair<int,int> pi;
const int N=1000005;
const int MOD=1000000007;
int n,l[N],r[N],jc[N],ny[N];
std::map<pi,int> ma;
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int C(int n,int m)
{
return (LL)jc[n]*ny[m]%MOD*ny[n-m]%MOD;
}
int solve(int l,int r)
{
if (l>r) return 1;
int x=ma[mp(l,r)];
if (!x) return 0;
return (LL)solve(l,x-1)*solve(x+1,r)%MOD*C(r-l,x-l)%MOD;
}
int main()
{
int T=0;
while (scanf("%d",&n)!=EOF)
{
T++;
printf("Case #%d: ",T);
ma.clear();
jc[0]=jc[1]=ny[0]=ny[1]=1;
for (int i=2;i<=n;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
for (int i=2;i<=n;i++) ny[i]=(LL)ny[i-1]*ny[i]%MOD;
for (int i=1;i<=n;i++) l[i]=read();
for (int i=1;i<=n;i++) r[i]=read();
for (int i=1;i<=n;i++) ma[mp(l[i],r[i])]=i;
printf("%d\n",solve(1,n));
}
return 0;
}