对于一个 11 到 nn 的排列 p1,p2,⋯,pnp1,p2,⋯,pn ,我们可以轻松地对于任意的 1≤i≤n1≤i≤n 计算出 (li,ri)(li,ri) ,使得对于任意的 1≤L≤R≤n1≤L≤R≤n 来说 min(pL,pL+1,⋯,pR)=pimin(pL,pL+1,⋯,pR)=pi 当且仅当 li≤L≤i≤R≤rili≤L≤i≤R≤ri 。
给定整数 nn 和 (li,ri)(li,ri) (1≤i≤n)(1≤i≤n) ,你需要计算有多少种可能的 11 到 nn 的排列 p1,p2,⋯,pnp1,p2,⋯,pn 满足上述条件。
由于答案可能很大,你只需要给出答案对 109+7109+7 取模的值。
Input每个测试点包含多组测试数据,不超过 5000 组。
对于每组测试数据:
第一行包含一个正整数 n ,满足 1 ≤ n ≤ 10^6 。
第二行包含 n 个正整数 l_1, l_2, ..., l_n ,对于 i = 1, 2, ..., n 满足 1 ≤ l_i ≤ i 。
第三行包含 n 个正整数 r_1, r_2, ..., r_n ,对于 i = 1, 2, ..., n 满足 i ≤ r_i ≤ n 。
保证每个测试点的所有测试数据的 n 之和不超过 3*10^6 。
每个测试点的输入数据不超过 40MiB ,请做好读入优化。Output对于每组测试数据,输出一行"Case #x: y"(不含引号),其中 x 表示测试数据的编号(从 1 开始), y 表示这组数据的答案对 10^9+7 取模的值。Sample Input
3 1 1 3 1 3 3
Sample Output
Case #1: 2
思路:用solve(L,R)表示当前区间的排列方案数,显然最大的一个数贯穿整个区间,不难找到这个最大的数的位置pos,那么把最大的数安置在pos位置处,然后挑选pos-L个数到pos的左边,剩下的到右边,变为solve(L,pos-1)*solve(pos+1,R);
(这里用map来找最大位置。普通的输入优化还是TEL
#include<bits/stdc++.h> #define ll long long using namespace std; const int Mod=1e9+7; const int maxn=1000000; int L[maxn+10],pre[maxn+10],lat[maxn+10]; int fac[maxn+10],rev[maxn+10],ans,N,Case=0; ; map<pair<int,int>,int >mp; void read(int &x){ x=0; char c=getchar(); while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar(); } void solve(int l,int r) { if(l>r) return ; int pos=mp[make_pair(l,r)]; if(pos>r||pos<l){ ans=0; return ;} ans=(ll)ans*fac[r-l]%Mod*rev[pos-l]%Mod*rev[r-pos]%Mod; solve(l,pos-1); solve(pos+1,r); } int main() { fac[0]=1; for(int i=1;i<=maxn;i++) fac[i]=(ll)fac[i-1]*i%Mod; rev[1]=1; for(int i=2;i<=maxn;i++) rev[i]=(ll)(Mod-Mod/i)*rev[Mod%i]%Mod; rev[0]=1; for(int i=2;i<=maxn;i++) rev[i]=(ll)rev[i-1]*rev[i]%Mod; while(~scanf("%d",&N)){ ans=1; mp.clear(); for(int i=1;i<=N;i++) read(pre[i]); for(int i=1;i<=N;i++) read(lat[i]); for(int i=1;i<=N;i++) mp[make_pair(pre[i],lat[i])]=i; solve(1,N); printf("Case #%d: %d ",++Case,ans); } return 0; }