中文題面:https://www.luogu.com.cn/problem/CF1946E
先考慮只要求字首最大值怎麼做。從前往後很容易想到\(O(n^3)\)的dp,用字首和最佳化可以到\(O(n^2)\).注意相對順序,\([p_i,p_{i+1}-1]\)選擇的數,必須讓最大的放在最前面才合法。比如選1,3,9,在[5,8]這個區間,只有9,1,3和9,3,1是合法的。從後往前考慮每一段,發現前面的選擇對後面沒有影響(相對順序不變)。
字尾最大值考慮的方法類似。注意判斷合法狀態。a[m1] != b[1] || a[1] != 1 || b[m2] != n, 即最大值在前字尾相同,字首第一個在1,字尾最後一個在n。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 1e9 + 7;
const int N = 2e5 + 11;
int a[N], b[N];
int n, m1, m2;
LL fac[N], invo[N], inv[N];
LL C(int n, int m){
return fac[n] * inv[m] % mod * inv[n-m] % mod;
}
void work(){
cin>>n>>m1>>m2;
for(int i = 1;i <= m1; i++){
scanf("%d", &a[i]);
}
for(int i = 1;i <= m2; i++){
scanf("%d", &b[i]);
}
if(a[m1] != b[1] || a[1] != 1 || b[m2] != n){
cout<<0<<endl;
return ;
}
LL res = C(n - 1, a[m1] - 1);
LL tmp = a[m1] - 1;
for(int i = m1 - 1;i >= 1; i--){
tmp--;
res = res * C(tmp, a[i+1] - a[i] - 1) % mod * fac[a[i+1]-a[i]-1] % mod;
tmp -= a[i+1] - a[i] - 1;
}
tmp = n - a[m1];
for(int i = 1;i < m2; i++){
tmp--;
res = res * C(tmp, b[i+1] - b[i] - 1) % mod * fac[b[i+1]-b[i]-1] % mod;
tmp -= b[i+1] - b[i] - 1;
}
cout<<res<<endl;
}
int main(){
int T;
cin>>T;
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i = 1;i <= 2e5; i++){
fac[i] = 1ll * fac[i-1] * i % mod;
}
for(int i = 2;i <= 2e5; i++){
inv[i] = (mod - mod / i) * inv[mod%i] % mod;
}
for(int i = 2;i <= 2e5; i++){
invo[i] = inv[i];
inv[i] = inv[i-1] * inv[i] % mod;
}
while(T--)work();
return 0;
}